diff --git a/node_modules/.bin/esbuild b/node_modules/.bin/esbuild deleted file mode 120000 index c83ac07..0000000 --- a/node_modules/.bin/esbuild +++ /dev/null @@ -1 +0,0 @@ -../esbuild/bin/esbuild \ No newline at end of file diff --git a/node_modules/.bin/nanoid b/node_modules/.bin/nanoid deleted file mode 120000 index e2be547..0000000 --- a/node_modules/.bin/nanoid +++ /dev/null @@ -1 +0,0 @@ -../nanoid/bin/nanoid.cjs \ No newline at end of file diff --git a/node_modules/.bin/rollup b/node_modules/.bin/rollup deleted file mode 120000 index 5939621..0000000 --- a/node_modules/.bin/rollup +++ /dev/null @@ -1 +0,0 @@ -../rollup/dist/bin/rollup \ No newline at end of file diff --git a/node_modules/.bin/vite b/node_modules/.bin/vite deleted file mode 120000 index 6d1e3be..0000000 --- a/node_modules/.bin/vite +++ /dev/null @@ -1 +0,0 @@ -../vite/bin/vite.js \ No newline at end of file diff --git a/node_modules/.vite/_metadata.json b/node_modules/.vite/_metadata.json deleted file mode 100644 index 604cffc..0000000 --- a/node_modules/.vite/_metadata.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "hash": "ee5cc2cf", - "browserHash": "7292be66", - "optimized": { - "neataptic": { - "file": "/home/satori/sakuya/node_modules/.vite/neataptic.js", - "src": "/home/satori/sakuya/node_modules/neataptic/src/neataptic.js", - "needsInterop": true - }, - "frappe-charts": { - "file": "/home/satori/sakuya/node_modules/.vite/frappe-charts.js", - "src": "/home/satori/sakuya/node_modules/frappe-charts/dist/frappe-charts.min.esm.js", - "needsInterop": false - }, - "p5": { - "file": "/home/satori/sakuya/node_modules/.vite/p5.js", - "src": "/home/satori/sakuya/node_modules/p5/lib/p5.min.js", - "needsInterop": true - } - } -} \ No newline at end of file diff --git a/node_modules/.vite/chunk-ELXAK55F.js b/node_modules/.vite/chunk-ELXAK55F.js deleted file mode 100644 index bfe9a46..0000000 --- a/node_modules/.vite/chunk-ELXAK55F.js +++ /dev/null @@ -1,28 +0,0 @@ -var __defProp = Object.defineProperty; -var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); -var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { - get: (a, b) => (typeof require !== "undefined" ? require : a)[b] -}) : x)(function(x) { - if (typeof require !== "undefined") - return require.apply(this, arguments); - throw new Error('Dynamic require of "' + x + '" is not supported'); -}); -var __esm = (fn, res) => function __init() { - return fn && (res = (0, fn[Object.keys(fn)[0]])(fn = 0)), res; -}; -var __commonJS = (cb, mod) => function __require2() { - return mod || (0, cb[Object.keys(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; -}; -var __export = (target, all) => { - __markAsModule(target); - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); -}; - -export { - __require, - __esm, - __commonJS, - __export -}; -//# sourceMappingURL=chunk-ELXAK55F.js.map diff --git a/node_modules/.vite/chunk-ELXAK55F.js.map b/node_modules/.vite/chunk-ELXAK55F.js.map deleted file mode 100644 index 9865211..0000000 --- a/node_modules/.vite/chunk-ELXAK55F.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": [], - "sourcesContent": [], - "mappings": "", - "names": [] -} diff --git a/node_modules/.vite/frappe-charts.js b/node_modules/.vite/frappe-charts.js deleted file mode 100644 index 5f18274..0000000 --- a/node_modules/.vite/frappe-charts.js +++ /dev/null @@ -1,1988 +0,0 @@ -import "./chunk-ELXAK55F.js"; - -// node_modules/frappe-charts/dist/frappe-charts.min.esm.js -function styleInject(t7, e) { - e === void 0 && (e = {}); - var n = e.insertAt; - if (t7 && typeof document != "undefined") { - var i = document.head || document.getElementsByTagName("head")[0], a = document.createElement("style"); - a.type = "text/css", n === "top" && i.firstChild ? i.insertBefore(a, i.firstChild) : i.appendChild(a), a.styleSheet ? a.styleSheet.cssText = t7 : a.appendChild(document.createTextNode(t7)); - } -} -function $(t7, e) { - return typeof t7 == "string" ? (e || document).querySelector(t7) : t7 || null; -} -function getOffset(t7) { - var e = t7.getBoundingClientRect(); - return { top: e.top + (document.documentElement.scrollTop || document.body.scrollTop), left: e.left + (document.documentElement.scrollLeft || document.body.scrollLeft) }; -} -function isHidden(t7) { - return t7.offsetParent === null; -} -function isElementInViewport(t7) { - var e = t7.getBoundingClientRect(); - return e.top >= 0 && e.left >= 0 && e.bottom <= (window.innerHeight || document.documentElement.clientHeight) && e.right <= (window.innerWidth || document.documentElement.clientWidth); -} -function getElementContentWidth(t7) { - var e = window.getComputedStyle(t7), n = parseFloat(e.paddingLeft) + parseFloat(e.paddingRight); - return t7.clientWidth - n; -} -function fire(t7, e, n) { - var i = document.createEvent("HTMLEvents"); - i.initEvent(e, true, true); - for (var a in n) - i[a] = n[a]; - return t7.dispatchEvent(i); -} -function getTopOffset(t7) { - return t7.titleHeight + t7.margins.top + t7.paddings.top; -} -function getLeftOffset(t7) { - return t7.margins.left + t7.paddings.left; -} -function getExtraHeight(t7) { - return t7.margins.top + t7.margins.bottom + t7.paddings.top + t7.paddings.bottom + t7.titleHeight + t7.legendHeight; -} -function getExtraWidth(t7) { - return t7.margins.left + t7.margins.right + t7.paddings.left + t7.paddings.right; -} -function _classCallCheck$4(t7, e) { - if (!(t7 instanceof e)) - throw new TypeError("Cannot call a class as a function"); -} -function floatTwo(t7) { - return parseFloat(t7.toFixed(2)); -} -function fillArray(t7, e, n) { - var i = arguments.length > 3 && arguments[3] !== void 0 && arguments[3]; - n || (n = i ? t7[0] : t7[t7.length - 1]); - var a = new Array(Math.abs(e)).fill(n); - return t7 = i ? a.concat(t7) : t7.concat(a); -} -function getStringWidth(t7, e) { - return (t7 + "").length * e; -} -function getPositionByAngle(t7, e) { - return { x: Math.sin(t7 * ANGLE_RATIO) * e, y: Math.cos(t7 * ANGLE_RATIO) * e }; -} -function isValidNumber(t7) { - var e = arguments.length > 1 && arguments[1] !== void 0 && arguments[1]; - return !Number.isNaN(t7) && (t7 !== void 0 && (!!Number.isFinite(t7) && !(e && t7 < 0))); -} -function round(t7) { - return Number(Math.round(t7 + "e4") + "e-4"); -} -function deepClone(t7) { - var e = void 0, n = void 0, i = void 0; - if (t7 instanceof Date) - return new Date(t7.getTime()); - if ((t7 === void 0 ? "undefined" : _typeof$2(t7)) !== "object" || t7 === null) - return t7; - e = Array.isArray(t7) ? [] : {}; - for (i in t7) - n = t7[i], e[i] = deepClone(n); - return e; -} -function getBarHeightAndYAttr(t7, e) { - var n = void 0, i = void 0; - return t7 <= e ? (n = e - t7, i = t7) : (n = t7 - e, i = e), [n, i]; -} -function equilizeNoOfElements(t7, e) { - var n = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : e.length - t7.length; - return n > 0 ? t7 = fillArray(t7, n) : e = fillArray(e, n), [t7, e]; -} -function truncateString(t7, e) { - if (t7) - return t7.length > e ? t7.slice(0, e - 3) + "..." : t7; -} -function shortenLargeNumber(t7) { - var e = void 0; - if (typeof t7 == "number") - e = t7; - else if (typeof t7 == "string" && (e = Number(t7), Number.isNaN(e))) - return t7; - var n = Math.floor(Math.log10(Math.abs(e))); - if (n <= 2) - return e; - var i = Math.floor(n / 3), a = Math.pow(10, n - 3 * i) * +(e / Math.pow(10, n)).toFixed(1); - return Math.round(100 * a) / 100 + " " + ["", "K", "M", "B", "T"][i]; -} -function getSplineCurvePointsStr(t7, e) { - for (var n = [], i = 0; i < t7.length; i++) - n.push([t7[i], e[i]]); - var a = function(t8, e2) { - var n2 = e2[0] - t8[0], i2 = e2[1] - t8[1]; - return { length: Math.sqrt(Math.pow(n2, 2) + Math.pow(i2, 2)), angle: Math.atan2(i2, n2) }; - }, r = function(t8, e2, n2, i2) { - var r2 = a(e2 || t8, n2 || t8), o = r2.angle + (i2 ? Math.PI : 0), s = 0.2 * r2.length; - return [t8[0] + Math.cos(o) * s, t8[1] + Math.sin(o) * s]; - }; - return function(t8, e2) { - return t8.reduce(function(t9, n2, i2, a2) { - return i2 === 0 ? n2[0] + "," + n2[1] : t9 + " " + e2(n2, i2, a2); - }, ""); - }(n, function(t8, e2, n2) { - var i2 = r(n2[e2 - 1], n2[e2 - 2], t8), a2 = r(t8, n2[e2 - 1], n2[e2 + 1], true); - return "C " + i2[0] + "," + i2[1] + " " + a2[0] + "," + a2[1] + " " + t8[0] + "," + t8[1]; - }); -} -function limitColor(t7) { - return t7 > 255 ? 255 : t7 < 0 ? 0 : t7; -} -function lightenDarkenColor(t7, e) { - var n = getColor(t7), i = false; - n[0] == "#" && (n = n.slice(1), i = true); - var a = parseInt(n, 16), r = limitColor((a >> 16) + e), o = limitColor((a >> 8 & 255) + e), s = limitColor((255 & a) + e); - return (i ? "#" : "") + (s | o << 8 | r << 16).toString(16); -} -function isValidColor(t7) { - var e = /(^\s*)(rgb|hsl)(a?)[(]\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*(?:,\s*([\d.]+)\s*)?[)]$/i; - return /(^\s*)(#)((?:[A-Fa-f0-9]{3}){1,2})$/i.test(t7) || e.test(t7); -} -function $$1(t7, e) { - return typeof t7 == "string" ? (e || document).querySelector(t7) : t7 || null; -} -function createSVG(t7, e) { - var n = document.createElementNS("http://www.w3.org/2000/svg", t7); - for (var i in e) { - var a = e[i]; - if (i === "inside") - $$1(a).appendChild(n); - else if (i === "around") { - var r = $$1(a); - r.parentNode.insertBefore(n, r), n.appendChild(r); - } else - i === "styles" ? (a === void 0 ? "undefined" : _typeof$1(a)) === "object" && Object.keys(a).map(function(t8) { - n.style[t8] = a[t8]; - }) : (i === "className" && (i = "class"), i === "innerHTML" ? n.textContent = a : n.setAttribute(i, a)); - } - return n; -} -function renderVerticalGradient(t7, e) { - return createSVG("linearGradient", { inside: t7, id: e, x1: 0, x2: 0, y1: 0, y2: 1 }); -} -function setGradientStop(t7, e, n, i) { - return createSVG("stop", { inside: t7, style: "stop-color: " + n, offset: e, "stop-opacity": i }); -} -function makeSVGContainer(t7, e, n, i) { - return createSVG("svg", { className: e, inside: t7, width: n, height: i }); -} -function makeSVGDefs(t7) { - return createSVG("defs", { inside: t7 }); -} -function makeSVGGroup(t7) { - var e = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "", n = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : void 0, i = { className: t7, transform: e }; - return n && (i.inside = n), createSVG("g", i); -} -function makePath(t7) { - return createSVG("path", { className: arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "", d: t7, styles: { stroke: arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : "none", fill: arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : "none", "stroke-width": arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : 2 } }); -} -function makeArcPathStr(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : 1, r = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : 0, o = n.x + t7.x, s = n.y + t7.y, l = n.x + e.x, u = n.y + e.y; - return "M" + n.x + " " + n.y + "\n L" + o + " " + s + "\n A " + i + " " + i + " 0 " + r + " " + (a ? 1 : 0) + "\n " + l + " " + u + " z"; -} -function makeCircleStr(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : 1, r = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : 0, o = n.x + t7.x, s = n.y + t7.y, l = n.x + e.x, u = 2 * n.y, c = n.y + e.y; - return "M" + n.x + " " + n.y + "\n L" + o + " " + s + "\n A " + i + " " + i + " 0 " + r + " " + (a ? 1 : 0) + "\n " + l + " " + u + " z\n L" + o + " " + u + "\n A " + i + " " + i + " 0 " + r + " " + (a ? 1 : 0) + "\n " + l + " " + c + " z"; -} -function makeArcStrokePathStr(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : 1, r = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : 0, o = n.x + t7.x, s = n.y + t7.y, l = n.x + e.x, u = n.y + e.y; - return "M" + o + " " + s + "\n A " + i + " " + i + " 0 " + r + " " + (a ? 1 : 0) + "\n " + l + " " + u; -} -function makeStrokeCircleStr(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : 1, r = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : 0, o = n.x + t7.x, s = n.y + t7.y, l = n.x + e.x, u = 2 * i + s, c = n.y + t7.y; - return "M" + o + " " + s + "\n A " + i + " " + i + " 0 " + r + " " + (a ? 1 : 0) + "\n " + l + " " + u + "\n M" + o + " " + u + "\n A " + i + " " + i + " 0 " + r + " " + (a ? 1 : 0) + "\n " + l + " " + c; -} -function makeGradient(t7, e) { - var n = arguments.length > 2 && arguments[2] !== void 0 && arguments[2], i = "path-fill-gradient-" + e + "-" + (n ? "lighter" : "default"), a = renderVerticalGradient(t7, i), r = [1, 0.6, 0.2]; - return n && (r = [0.4, 0.2, 0]), setGradientStop(a, "0%", e, r[0]), setGradientStop(a, "50%", e, r[1]), setGradientStop(a, "100%", e, r[2]), i; -} -function percentageBar(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : PERCENTAGE_BAR_DEFAULT_DEPTH, r = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : "none"; - return createSVG("rect", { className: "percentage-bar", x: t7, y: e, width: n, height: i, fill: r, styles: { stroke: lightenDarkenColor(r, -25), "stroke-dasharray": "0, " + (i + n) + ", " + n + ", " + i, "stroke-width": a } }); -} -function heatSquare(t7, e, n, i, a) { - var r = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : "none", o = arguments.length > 6 && arguments[6] !== void 0 ? arguments[6] : {}, s = { className: t7, x: e, y: n, width: i, height: i, rx: a, fill: r }; - return Object.keys(o).map(function(t8) { - s[t8] = o[t8]; - }), createSVG("rect", s); -} -function legendBar(t7, e, n) { - var i = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : "none", a = arguments[4]; - a = arguments.length > 5 && arguments[5] !== void 0 && arguments[5] ? truncateString(a, LABEL_MAX_CHARS) : a; - var r = { className: "legend-bar", x: 0, y: 0, width: n, height: "2px", fill: i }, o = createSVG("text", { className: "legend-dataset-text", x: 0, y: 0, dy: 2 * FONT_SIZE + "px", "font-size": 1.2 * FONT_SIZE + "px", "text-anchor": "start", fill: FONT_FILL, innerHTML: a }), s = createSVG("g", { transform: "translate(" + t7 + ", " + e + ")" }); - return s.appendChild(createSVG("rect", r)), s.appendChild(o), s; -} -function legendDot(t7, e, n) { - var i = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : "none", a = arguments[4]; - a = arguments.length > 5 && arguments[5] !== void 0 && arguments[5] ? truncateString(a, LABEL_MAX_CHARS) : a; - var r = { className: "legend-dot", cx: 0, cy: 0, r: n, fill: i }, o = createSVG("text", { className: "legend-dataset-text", x: 0, y: 0, dx: FONT_SIZE + "px", dy: FONT_SIZE / 3 + "px", "font-size": 1.2 * FONT_SIZE + "px", "text-anchor": "start", fill: FONT_FILL, innerHTML: a }), s = createSVG("g", { transform: "translate(" + t7 + ", " + e + ")" }); - return s.appendChild(createSVG("circle", r)), s.appendChild(o), s; -} -function makeText(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : {}, r = a.fontSize || FONT_SIZE; - return createSVG("text", { className: t7, x: e, y: n, dy: (a.dy !== void 0 ? a.dy : r / 2) + "px", "font-size": r + "px", fill: a.fill || FONT_FILL, "text-anchor": a.textAnchor || "start", innerHTML: i }); -} -function makeVertLine(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : {}; - a.stroke || (a.stroke = BASE_LINE_COLOR); - var r = createSVG("line", { className: "line-vertical " + a.className, x1: 0, x2: 0, y1: n, y2: i, styles: { stroke: a.stroke } }), o = createSVG("text", { x: 0, y: n > i ? n + LABEL_MARGIN : n - LABEL_MARGIN - FONT_SIZE, dy: FONT_SIZE + "px", "font-size": FONT_SIZE + "px", "text-anchor": "middle", innerHTML: e + "" }), s = createSVG("g", { transform: "translate(" + t7 + ", 0)" }); - return s.appendChild(r), s.appendChild(o), s; -} -function makeHoriLine(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : {}; - a.stroke || (a.stroke = BASE_LINE_COLOR), a.lineType || (a.lineType = ""), a.shortenNumbers && (e = shortenLargeNumber(e)); - var r = createSVG("line", { className: "line-horizontal " + a.className + (a.lineType === "dashed" ? "dashed" : ""), x1: n, x2: i, y1: 0, y2: 0, styles: { stroke: a.stroke } }), o = createSVG("text", { x: n < i ? n - LABEL_MARGIN : n + LABEL_MARGIN, y: 0, dy: FONT_SIZE / 2 - 2 + "px", "font-size": FONT_SIZE + "px", "text-anchor": n < i ? "end" : "start", innerHTML: e + "" }), s = createSVG("g", { transform: "translate(0, " + t7 + ")", "stroke-opacity": 1 }); - return o !== 0 && o !== "0" || (s.style.stroke = "rgba(27, 31, 35, 0.6)"), s.appendChild(r), s.appendChild(o), s; -} -function yLine(t7, e, n) { - var i = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {}; - isValidNumber(t7) || (t7 = 0), i.pos || (i.pos = "left"), i.offset || (i.offset = 0), i.mode || (i.mode = "span"), i.stroke || (i.stroke = BASE_LINE_COLOR), i.className || (i.className = ""); - var a = -1 * AXIS_TICK_LENGTH, r = i.mode === "span" ? n + AXIS_TICK_LENGTH : 0; - return i.mode === "tick" && i.pos === "right" && (a = n + AXIS_TICK_LENGTH, r = n), a += i.offset, r += i.offset, makeHoriLine(t7, e, a, r, { stroke: i.stroke, className: i.className, lineType: i.lineType, shortenNumbers: i.shortenNumbers }); -} -function xLine(t7, e, n) { - var i = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {}; - isValidNumber(t7) || (t7 = 0), i.pos || (i.pos = "bottom"), i.offset || (i.offset = 0), i.mode || (i.mode = "span"), i.stroke || (i.stroke = BASE_LINE_COLOR), i.className || (i.className = ""); - var a = n + AXIS_TICK_LENGTH, r = i.mode === "span" ? -1 * AXIS_TICK_LENGTH : n; - return i.mode === "tick" && i.pos === "top" && (a = -1 * AXIS_TICK_LENGTH, r = 0), makeVertLine(t7, e, a, r, { stroke: i.stroke, className: i.className, lineType: i.lineType }); -} -function yMarker(t7, e, n) { - var i = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {}; - i.labelPos || (i.labelPos = "right"); - var a = createSVG("text", { className: "chart-label", x: i.labelPos === "left" ? LABEL_MARGIN : n - getStringWidth(e, 5) - LABEL_MARGIN, y: 0, dy: FONT_SIZE / -2 + "px", "font-size": FONT_SIZE + "px", "text-anchor": "start", innerHTML: e + "" }), r = makeHoriLine(t7, "", 0, n, { stroke: i.stroke || BASE_LINE_COLOR, className: i.className || "", lineType: i.lineType }); - return r.appendChild(a), r; -} -function yRegion(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : {}, r = t7 - e, o = createSVG("rect", { className: "bar mini", styles: { fill: "rgba(228, 234, 239, 0.49)", stroke: BASE_LINE_COLOR, "stroke-dasharray": n + ", " + r }, x: 0, y: 0, width: n, height: r }); - a.labelPos || (a.labelPos = "right"); - var s = createSVG("text", { className: "chart-label", x: a.labelPos === "left" ? LABEL_MARGIN : n - getStringWidth(i + "", 4.5) - LABEL_MARGIN, y: 0, dy: FONT_SIZE / -2 + "px", "font-size": FONT_SIZE + "px", "text-anchor": "start", innerHTML: i + "" }), l = createSVG("g", { transform: "translate(0, " + e + ")" }); - return l.appendChild(o), l.appendChild(s), l; -} -function datasetBar(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : "", r = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : 0, o = arguments.length > 6 && arguments[6] !== void 0 ? arguments[6] : 0, s = arguments.length > 7 && arguments[7] !== void 0 ? arguments[7] : {}, l = getBarHeightAndYAttr(e, s.zeroLine), u = _slicedToArray(l, 2), c = u[0], h = u[1]; - h -= o, c === 0 && (c = s.minHeight, h -= s.minHeight), isValidNumber(t7) || (t7 = 0), isValidNumber(h) || (h = 0), isValidNumber(c, true) || (c = 0), isValidNumber(n, true) || (n = 0); - var d = createSVG("rect", { className: "bar mini", style: "fill: " + i, "data-point-index": r, x: t7, y: h, width: n, height: c }); - if ((a += "") || a.length) { - d.setAttribute("y", 0), d.setAttribute("x", 0); - var f = createSVG("text", { className: "data-point-value", x: n / 2, y: 0, dy: FONT_SIZE / 2 * -1 + "px", "font-size": FONT_SIZE + "px", "text-anchor": "middle", innerHTML: a }), p = createSVG("g", { "data-point-index": r, transform: "translate(" + t7 + ", " + h + ")" }); - return p.appendChild(d), p.appendChild(f), p; - } - return d; -} -function datasetDot(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : "", r = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : 0, o = createSVG("circle", { style: "fill: " + i, "data-point-index": r, cx: t7, cy: e, r: n }); - if ((a += "") || a.length) { - o.setAttribute("cy", 0), o.setAttribute("cx", 0); - var s = createSVG("text", { className: "data-point-value", x: 0, y: 0, dy: FONT_SIZE / 2 * -1 - n + "px", "font-size": FONT_SIZE + "px", "text-anchor": "middle", innerHTML: a }), l = createSVG("g", { "data-point-index": r, transform: "translate(" + t7 + ", " + e + ")" }); - return l.appendChild(o), l.appendChild(s), l; - } - return o; -} -function getPaths(t7, e, n) { - var i = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : {}, a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : {}, r = e.map(function(e2, n2) { - return t7[n2] + "," + e2; - }).join("L"); - i.spline && (r = getSplineCurvePointsStr(t7, e)); - var o = makePath("M" + r, "line-graph-path", n); - if (i.heatline) { - var s = makeGradient(a.svgDefs, n); - o.style.stroke = "url(#" + s + ")"; - } - var l = { path: o }; - if (i.regionFill) { - var u = makeGradient(a.svgDefs, n, true), c = "M" + t7[0] + "," + a.zeroLine + "L" + r + "L" + t7.slice(-1)[0] + "," + a.zeroLine; - l.region = makePath(c, "region-fill", "none", "url(#" + u + ")"); - } - return l; -} -function translate(t7, e, n, i) { - var a = typeof e == "string" ? e : e.join(", "); - return [t7, { transform: n.join(", ") }, i, STD_EASING, "translate", { transform: a }]; -} -function translateVertLine(t7, e, n) { - return translate(t7, [n, 0], [e, 0], MARKER_LINE_ANIM_DUR); -} -function translateHoriLine(t7, e, n) { - return translate(t7, [0, n], [0, e], MARKER_LINE_ANIM_DUR); -} -function animateRegion(t7, e, n, i) { - var a = e - n, r = t7.childNodes[0]; - return [[r, { height: a, "stroke-dasharray": r.getAttribute("width") + ", " + a }, MARKER_LINE_ANIM_DUR, STD_EASING], translate(t7, [0, i], [0, n], MARKER_LINE_ANIM_DUR)]; -} -function animateBar(t7, e, n, i) { - var a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : 0, r = getBarHeightAndYAttr(n, (arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : {}).zeroLine), o = _slicedToArray$2(r, 2), s = o[0], l = o[1]; - return l -= a, t7.nodeName !== "rect" ? [[t7.childNodes[0], { width: i, height: s }, UNIT_ANIM_DUR, STD_EASING], translate(t7, t7.getAttribute("transform").split("(")[1].slice(0, -1), [e, l], MARKER_LINE_ANIM_DUR)] : [[t7, { width: i, height: s, x: e, y: l }, UNIT_ANIM_DUR, STD_EASING]]; -} -function animateDot(t7, e, n) { - return t7.nodeName !== "circle" ? [translate(t7, t7.getAttribute("transform").split("(")[1].slice(0, -1), [e, n], MARKER_LINE_ANIM_DUR)] : [[t7, { cx: e, cy: n }, UNIT_ANIM_DUR, STD_EASING]]; -} -function animatePath(t7, e, n, i, a) { - var r = [], o = n.map(function(t8, n2) { - return e[n2] + "," + t8; - }).join("L"); - a && (o = getSplineCurvePointsStr(e, n)); - var s = [t7.path, { d: "M" + o }, PATH_ANIM_DUR, STD_EASING]; - if (r.push(s), t7.region) { - var l = e[0] + "," + i + "L", u = "L" + e.slice(-1)[0] + ", " + i, c = [t7.region, { d: "M" + l + o + u }, PATH_ANIM_DUR, STD_EASING]; - r.push(c); - } - return r; -} -function animatePathStr(t7, e) { - return [t7, { d: e }, UNIT_ANIM_DUR, STD_EASING]; -} -function _toConsumableArray$1(t7) { - if (Array.isArray(t7)) { - for (var e = 0, n = Array(t7.length); e < t7.length; e++) - n[e] = t7[e]; - return n; - } - return Array.from(t7); -} -function animateSVGElement(t7, e, n) { - var i = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : "linear", a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : void 0, r = arguments.length > 5 && arguments[5] !== void 0 ? arguments[5] : {}, o = t7.cloneNode(true), s = t7.cloneNode(true); - for (var l in e) { - var u = void 0; - u = l === "transform" ? document.createElementNS("http://www.w3.org/2000/svg", "animateTransform") : document.createElementNS("http://www.w3.org/2000/svg", "animate"); - var c = r[l] || t7.getAttribute(l), h = e[l], d = { attributeName: l, from: c, to: h, begin: "0s", dur: n / 1e3 + "s", values: c + ";" + h, keySplines: EASING[i], keyTimes: "0;1", calcMode: "spline", fill: "freeze" }; - a && (d.type = a); - for (var f in d) - u.setAttribute(f, d[f]); - o.appendChild(u), a ? s.setAttribute(l, "translate(" + h + ")") : s.setAttribute(l, h); - } - return [o, s]; -} -function transform(t7, e) { - t7.style.transform = e, t7.style.webkitTransform = e, t7.style.msTransform = e, t7.style.mozTransform = e, t7.style.oTransform = e; -} -function animateSVG(t7, e) { - var n = [], i = []; - e.map(function(t8) { - var e2 = t8[0], a2 = e2.parentNode, r = void 0, o = void 0; - t8[0] = e2; - var s = animateSVGElement.apply(void 0, _toConsumableArray$1(t8)), l = _slicedToArray$1(s, 2); - r = l[0], o = l[1], n.push(o), i.push([r, a2]), a2 && a2.replaceChild(r, e2); - }); - var a = t7.cloneNode(true); - return i.map(function(t8, i2) { - t8[1] && (t8[1].replaceChild(n[i2], t8[0]), e[i2][0] = n[i2]); - }), a; -} -function runSMILAnimation(t7, e, n) { - if (n.length !== 0) { - var i = animateSVG(e, n); - e.parentNode == t7 && (t7.removeChild(e), t7.appendChild(i)), setTimeout(function() { - i.parentNode == t7 && (t7.removeChild(i), t7.appendChild(e)); - }, REPLACE_ALL_NEW_DUR); - } -} -function downloadFile(t7, e) { - var n = document.createElement("a"); - n.style = "display: none"; - var i = new Blob(e, { type: "image/svg+xml; charset=utf-8" }), a = window.URL.createObjectURL(i); - n.href = a, n.download = t7, document.body.appendChild(n), n.click(), setTimeout(function() { - document.body.removeChild(n), window.URL.revokeObjectURL(a); - }, 300); -} -function prepareForExport(t7) { - var e = t7.cloneNode(true); - e.classList.add("chart-container"), e.setAttribute("xmlns", "http://www.w3.org/2000/svg"), e.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); - var n = $.create("style", { innerHTML: CSSTEXT }); - e.insertBefore(n, e.firstChild); - var i = $.create("div"); - return i.appendChild(e), i.innerHTML; -} -function _classCallCheck$3(t7, e) { - if (!(t7 instanceof e)) - throw new TypeError("Cannot call a class as a function"); -} -function _classCallCheck$2(t7, e) { - if (!(t7 instanceof e)) - throw new TypeError("Cannot call a class as a function"); -} -function _possibleConstructorReturn$1(t7, e) { - if (!t7) - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || typeof e != "object" && typeof e != "function" ? t7 : e; -} -function _inherits$1(t7, e) { - if (typeof e != "function" && e !== null) - throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t7.prototype = Object.create(e && e.prototype, { constructor: { value: t7, enumerable: false, writable: true, configurable: true } }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t7, e) : t7.__proto__ = e); -} -function treatAsUtc(t7) { - var e = new Date(t7); - return e.setMinutes(e.getMinutes() - e.getTimezoneOffset()), e; -} -function getYyyyMmDd(t7) { - var e = t7.getDate(), n = t7.getMonth() + 1; - return [t7.getFullYear(), (n > 9 ? "" : "0") + n, (e > 9 ? "" : "0") + e].join("-"); -} -function clone(t7) { - return new Date(t7.getTime()); -} -function getWeeksBetween(t7, e) { - var n = setDayToSunday(t7); - return Math.ceil(getDaysBetween(n, e) / NO_OF_DAYS_IN_WEEK); -} -function getDaysBetween(t7, e) { - var n = SEC_IN_DAY * NO_OF_MILLIS; - return (treatAsUtc(e) - treatAsUtc(t7)) / n; -} -function areInSameMonth(t7, e) { - return t7.getMonth() === e.getMonth() && t7.getFullYear() === e.getFullYear(); -} -function getMonthName(t7) { - var e = arguments.length > 1 && arguments[1] !== void 0 && arguments[1], n = MONTH_NAMES[t7]; - return e ? n.slice(0, 3) : n; -} -function getLastDateInMonth(t7, e) { - return new Date(e, t7 + 1, 0); -} -function setDayToSunday(t7) { - var e = clone(t7), n = e.getDay(); - return n !== 0 && addDays(e, -1 * n), e; -} -function addDays(t7, e) { - t7.setDate(t7.getDate() + e); -} -function _classCallCheck$5(t7, e) { - if (!(t7 instanceof e)) - throw new TypeError("Cannot call a class as a function"); -} -function getComponent(t7, e, n) { - var i = Object.keys(componentConfigs).filter(function(e2) { - return t7.includes(e2); - }), a = componentConfigs[i[0]]; - return Object.assign(a, { constants: e, getData: n }), new ChartComponent(a); -} -function _toConsumableArray(t7) { - if (Array.isArray(t7)) { - for (var e = 0, n = Array(t7.length); e < t7.length; e++) - n[e] = t7[e]; - return n; - } - return Array.from(t7); -} -function _classCallCheck$1(t7, e) { - if (!(t7 instanceof e)) - throw new TypeError("Cannot call a class as a function"); -} -function _possibleConstructorReturn(t7, e) { - if (!t7) - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || typeof e != "object" && typeof e != "function" ? t7 : e; -} -function _inherits(t7, e) { - if (typeof e != "function" && e !== null) - throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t7.prototype = Object.create(e && e.prototype, { constructor: { value: t7, enumerable: false, writable: true, configurable: true } }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t7, e) : t7.__proto__ = e); -} -function _toConsumableArray$2(t7) { - if (Array.isArray(t7)) { - for (var e = 0, n = Array(t7.length); e < t7.length; e++) - n[e] = t7[e]; - return n; - } - return Array.from(t7); -} -function _classCallCheck$6(t7, e) { - if (!(t7 instanceof e)) - throw new TypeError("Cannot call a class as a function"); -} -function _possibleConstructorReturn$2(t7, e) { - if (!t7) - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || typeof e != "object" && typeof e != "function" ? t7 : e; -} -function _inherits$2(t7, e) { - if (typeof e != "function" && e !== null) - throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t7.prototype = Object.create(e && e.prototype, { constructor: { value: t7, enumerable: false, writable: true, configurable: true } }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t7, e) : t7.__proto__ = e); -} -function _toConsumableArray$4(t7) { - if (Array.isArray(t7)) { - for (var e = 0, n = Array(t7.length); e < t7.length; e++) - n[e] = t7[e]; - return n; - } - return Array.from(t7); -} -function normalize(t7) { - if (t7 === 0) - return [0, 0]; - if (isNaN(t7)) - return { mantissa: -6755399441055744, exponent: 972 }; - var e = t7 > 0 ? 1 : -1; - if (!isFinite(t7)) - return { mantissa: 4503599627370496 * e, exponent: 972 }; - t7 = Math.abs(t7); - var n = Math.floor(Math.log10(t7)); - return [e * (t7 / Math.pow(10, n)), n]; -} -function getChartRangeIntervals(t7) { - var e = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0, n = Math.ceil(t7), i = Math.floor(e), a = n - i, r = a, o = 1; - a > 5 && (a % 2 != 0 && (a = ++n - i), r = a / 2, o = 2), a <= 2 && (o = a / (r = 4)), a === 0 && (r = 5, o = 1); - for (var s = [], l = 0; l <= r; l++) - s.push(i + o * l); - return s; -} -function getChartIntervals(t7) { - var e = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0, n = normalize(t7), i = _slicedToArray$4(n, 2), a = i[0], r = i[1], o = e ? e / Math.pow(10, r) : 0, s = getChartRangeIntervals(a = a.toFixed(6), o); - return s = s.map(function(t8) { - return t8 * Math.pow(10, r); - }); -} -function calcChartIntervals(t7) { - function e(t8, e2) { - for (var n2 = getChartIntervals(t8), i2 = n2[1] - n2[0], a2 = 0, r2 = 1; a2 < e2; r2++) - a2 += i2, n2.unshift(-1 * a2); - return n2; - } - var n = arguments.length > 1 && arguments[1] !== void 0 && arguments[1], i = Math.max.apply(Math, _toConsumableArray$4(t7)), a = Math.min.apply(Math, _toConsumableArray$4(t7)), r = []; - if (i >= 0 && a >= 0) - normalize(i)[1], r = n ? getChartIntervals(i, a) : getChartIntervals(i); - else if (i > 0 && a < 0) { - var o = Math.abs(a); - i >= o ? (normalize(i)[1], r = e(i, o)) : (normalize(o)[1], r = e(o, i).reverse().map(function(t8) { - return -1 * t8; - })); - } else if (i <= 0 && a <= 0) { - var s = Math.abs(a), l = Math.abs(i); - normalize(s)[1], r = (r = n ? getChartIntervals(s, l) : getChartIntervals(s)).reverse().map(function(t8) { - return -1 * t8; - }); - } - return r; -} -function getZeroIndex(t7) { - var e = getIntervalSize(t7); - return t7.indexOf(0) >= 0 ? t7.indexOf(0) : t7[0] > 0 ? -1 * t7[0] / e : -1 * t7[t7.length - 1] / e + (t7.length - 1); -} -function getIntervalSize(t7) { - return t7[1] - t7[0]; -} -function getValueRange(t7) { - return t7[t7.length - 1] - t7[0]; -} -function scale(t7, e) { - return floatTwo(e.zeroLine - t7 * e.scaleMultiplier); -} -function getClosestInArray(t7, e) { - var n = arguments.length > 2 && arguments[2] !== void 0 && arguments[2], i = e.reduce(function(e2, n2) { - return Math.abs(n2 - t7) < Math.abs(e2 - t7) ? n2 : e2; - }, []); - return n ? e.indexOf(i) : i; -} -function calcDistribution(t7, e) { - for (var n = Math.max.apply(Math, _toConsumableArray$4(t7)), i = 1 / (e - 1), a = [], r = 0; r < e; r++) { - var o = n * (i * r); - a.push(o); - } - return a; -} -function getMaxCheckpoint(t7, e) { - return e.filter(function(e2) { - return e2 < t7; - }).length; -} -function _toConsumableArray$3(t7) { - if (Array.isArray(t7)) { - for (var e = 0, n = Array(t7.length); e < t7.length; e++) - n[e] = t7[e]; - return n; - } - return Array.from(t7); -} -function _classCallCheck$7(t7, e) { - if (!(t7 instanceof e)) - throw new TypeError("Cannot call a class as a function"); -} -function _possibleConstructorReturn$3(t7, e) { - if (!t7) - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || typeof e != "object" && typeof e != "function" ? t7 : e; -} -function _inherits$3(t7, e) { - if (typeof e != "function" && e !== null) - throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t7.prototype = Object.create(e && e.prototype, { constructor: { value: t7, enumerable: false, writable: true, configurable: true } }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t7, e) : t7.__proto__ = e); -} -function _toConsumableArray$6(t7) { - if (Array.isArray(t7)) { - for (var e = 0, n = Array(t7.length); e < t7.length; e++) - n[e] = t7[e]; - return n; - } - return Array.from(t7); -} -function dataPrep(t7, e) { - t7.labels = t7.labels || []; - var n = t7.labels.length, i = t7.datasets, a = new Array(n).fill(0); - return i || (i = [{ values: a }]), i.map(function(t8) { - if (t8.values) { - var i2 = t8.values; - i2 = (i2 = i2.map(function(t9) { - return isNaN(t9) ? 0 : t9; - })).length > n ? i2.slice(0, n) : fillArray(i2, n - i2.length, 0), t8.values = i2; - } else - t8.values = a; - t8.chartType || (AXIS_DATASET_CHART_TYPES.includes(e), t8.chartType = e); - }), t7.yRegions && t7.yRegions.map(function(t8) { - if (t8.end < t8.start) { - var e2 = [t8.end, t8.start]; - t8.start = e2[0], t8.end = e2[1]; - } - }), t7; -} -function zeroDataPrep(t7) { - var e = t7.labels.length, n = new Array(e).fill(0), i = { labels: t7.labels.slice(0, -1), datasets: t7.datasets.map(function(t8) { - return { name: "", values: n.slice(0, -1), chartType: t8.chartType }; - }) }; - return t7.yMarkers && (i.yMarkers = [{ value: 0, label: "" }]), t7.yRegions && (i.yRegions = [{ start: 0, end: 0, label: "" }]), i; -} -function getShortenedLabels(t7) { - var e = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : [], n = !(arguments.length > 2 && arguments[2] !== void 0) || arguments[2], i = t7 / e.length; - i <= 0 && (i = 1); - var a = i / DEFAULT_CHAR_WIDTH, r = void 0; - if (n) { - var o = Math.max.apply(Math, _toConsumableArray$6(e.map(function(t8) { - return t8.length; - }))); - r = Math.ceil(o / a); - } - return e.map(function(t8, e2) { - return (t8 += "").length > a && (n ? e2 % r != 0 && (t8 = "") : t8 = a - 3 > 0 ? t8.slice(0, a - 3) + " ..." : t8.slice(0, a) + ".."), t8; - }); -} -function _toConsumableArray$5(t7) { - if (Array.isArray(t7)) { - for (var e = 0, n = Array(t7.length); e < t7.length; e++) - n[e] = t7[e]; - return n; - } - return Array.from(t7); -} -function _classCallCheck$8(t7, e) { - if (!(t7 instanceof e)) - throw new TypeError("Cannot call a class as a function"); -} -function _possibleConstructorReturn$4(t7, e) { - if (!t7) - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || typeof e != "object" && typeof e != "function" ? t7 : e; -} -function _inherits$4(t7, e) { - if (typeof e != "function" && e !== null) - throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t7.prototype = Object.create(e && e.prototype, { constructor: { value: t7, enumerable: false, writable: true, configurable: true } }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t7, e) : t7.__proto__ = e); -} -function _toConsumableArray$7(t7) { - if (Array.isArray(t7)) { - for (var e = 0, n = Array(t7.length); e < t7.length; e++) - n[e] = t7[e]; - return n; - } - return Array.from(t7); -} -function _classCallCheck$9(t7, e) { - if (!(t7 instanceof e)) - throw new TypeError("Cannot call a class as a function"); -} -function _possibleConstructorReturn$5(t7, e) { - if (!t7) - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - return !e || typeof e != "object" && typeof e != "function" ? t7 : e; -} -function _inherits$5(t7, e) { - if (typeof e != "function" && e !== null) - throw new TypeError("Super expression must either be null or a function, not " + typeof e); - t7.prototype = Object.create(e && e.prototype, { constructor: { value: t7, enumerable: false, writable: true, configurable: true } }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t7, e) : t7.__proto__ = e); -} -function _classCallCheck(t7, e) { - if (!(t7 instanceof e)) - throw new TypeError("Cannot call a class as a function"); -} -function getChartByType() { - var t7 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "line", e = arguments[1], n = arguments[2]; - return t7 === "axis-mixed" ? (n.type = "line", new AxisChart(e, n)) : chartTypes[t7] ? new chartTypes[t7](e, n) : void console.error("Undefined chart type: " + t7); -} -var css_248z = '.chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ol,.graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}'; -styleInject(css_248z); -var _typeof = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(t7) { - return typeof t7; -} : function(t7) { - return t7 && typeof Symbol == "function" && t7.constructor === Symbol && t7 !== Symbol.prototype ? "symbol" : typeof t7; -}; -$.create = function(t7, e) { - var n = document.createElement(t7); - for (var i in e) { - var a = e[i]; - if (i === "inside") - $(a).appendChild(n); - else if (i === "around") { - var r = $(a); - r.parentNode.insertBefore(n, r), n.appendChild(r); - } else - i === "styles" ? (a === void 0 ? "undefined" : _typeof(a)) === "object" && Object.keys(a).map(function(t8) { - n.style[t8] = a[t8]; - }) : i in n ? n[i] = a : n.setAttribute(i, a); - } - return n; -}; -var BASE_MEASURES = { margins: { top: 10, bottom: 10, left: 20, right: 20 }, paddings: { top: 20, bottom: 40, left: 30, right: 10 }, baseHeight: 240, titleHeight: 20, legendHeight: 30, titleFontSize: 12 }; -var INIT_CHART_UPDATE_TIMEOUT = 700; -var CHART_POST_ANIMATE_TIMEOUT = 400; -var AXIS_DATASET_CHART_TYPES = ["line", "bar"]; -var AXIS_LEGEND_BAR_SIZE = 100; -var BAR_CHART_SPACE_RATIO = 0.5; -var MIN_BAR_PERCENT_HEIGHT = 0; -var LINE_CHART_DOT_SIZE = 4; -var DOT_OVERLAY_SIZE_INCR = 4; -var PERCENTAGE_BAR_DEFAULT_HEIGHT = 20; -var PERCENTAGE_BAR_DEFAULT_DEPTH = 2; -var HEATMAP_DISTRIBUTION_SIZE = 5; -var HEATMAP_SQUARE_SIZE = 10; -var HEATMAP_GUTTER_SIZE = 2; -var DEFAULT_CHAR_WIDTH = 7; -var TOOLTIP_POINTER_TRIANGLE_HEIGHT = 5; -var DEFAULT_CHART_COLORS = ["light-blue", "blue", "violet", "red", "orange", "yellow", "green", "light-green", "purple", "magenta", "light-grey", "dark-grey"]; -var HEATMAP_COLORS_GREEN = ["#ebedf0", "#c6e48b", "#7bc96f", "#239a3b", "#196127"]; -var DEFAULT_COLORS = { bar: DEFAULT_CHART_COLORS, line: DEFAULT_CHART_COLORS, pie: DEFAULT_CHART_COLORS, percentage: DEFAULT_CHART_COLORS, heatmap: HEATMAP_COLORS_GREEN, donut: DEFAULT_CHART_COLORS }; -var ANGLE_RATIO = Math.PI / 180; -var FULL_ANGLE = 360; -var _createClass$3 = function() { - function t7(t8, e) { - for (var n = 0; n < e.length; n++) { - var i = e[n]; - i.enumerable = i.enumerable || false, i.configurable = true, "value" in i && (i.writable = true), Object.defineProperty(t8, i.key, i); - } - } - return function(e, n, i) { - return n && t7(e.prototype, n), i && t7(e, i), e; - }; -}(); -var SvgTip = function() { - function t7(e) { - var n = e.parent, i = n === void 0 ? null : n, a = e.colors, r = a === void 0 ? [] : a; - _classCallCheck$4(this, t7), this.parent = i, this.colors = r, this.titleName = "", this.titleValue = "", this.listValues = [], this.titleValueFirst = 0, this.x = 0, this.y = 0, this.top = 0, this.left = 0, this.setup(); - } - return _createClass$3(t7, [{ key: "setup", value: function() { - this.makeTooltip(); - } }, { key: "refresh", value: function() { - this.fill(), this.calcPosition(); - } }, { key: "makeTooltip", value: function() { - var t8 = this; - this.container = $.create("div", { inside: this.parent, className: "graph-svg-tip comparison", innerHTML: '\n \n
' }), this.hideTip(), this.title = this.container.querySelector(".title"), this.dataPointList = this.container.querySelector(".data-point-list"), this.parent.addEventListener("mouseleave", function() { - t8.hideTip(); - }); - } }, { key: "fill", value: function() { - var t8 = this, e = void 0; - this.index && this.container.setAttribute("data-point-index", this.index), e = this.titleValueFirst ? "" + this.titleValue + "" + this.titleName : this.titleName + "" + this.titleValue + "", this.title.innerHTML = e, this.dataPointList.innerHTML = "", this.listValues.map(function(e2, n) { - var i = t8.colors[n] || "black", a = e2.formatted === 0 || e2.formatted ? e2.formatted : e2.value, r = $.create("li", { styles: { "border-top": "3px solid " + i }, innerHTML: '' + (a === 0 || a ? a : "") + "\n " + (e2.title ? e2.title : "") }); - t8.dataPointList.appendChild(r); - }); - } }, { key: "calcPosition", value: function() { - var t8 = this.container.offsetWidth; - this.top = this.y - this.container.offsetHeight - TOOLTIP_POINTER_TRIANGLE_HEIGHT, this.left = this.x - t8 / 2; - var e = this.parent.offsetWidth - t8, n = this.container.querySelector(".svg-pointer"); - if (this.left < 0) - n.style.left = "calc(50% - " + -1 * this.left + "px)", this.left = 0; - else if (this.left > e) { - var i = "calc(50% + " + (this.left - e) + "px)"; - n.style.left = i, this.left = e; - } else - n.style.left = "50%"; - } }, { key: "setValues", value: function(t8, e) { - var n = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : {}, i = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : [], a = arguments.length > 4 && arguments[4] !== void 0 ? arguments[4] : -1; - this.titleName = n.name, this.titleValue = n.value, this.listValues = i, this.x = t8, this.y = e, this.titleValueFirst = n.valueFirst || 0, this.index = a, this.refresh(); - } }, { key: "hideTip", value: function() { - this.container.style.top = "0px", this.container.style.left = "0px", this.container.style.opacity = "0"; - } }, { key: "showTip", value: function() { - this.container.style.top = this.top + "px", this.container.style.left = this.left + "px", this.container.style.opacity = "1"; - } }]), t7; -}(); -var _typeof$2 = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(t7) { - return typeof t7; -} : function(t7) { - return t7 && typeof Symbol == "function" && t7.constructor === Symbol && t7 !== Symbol.prototype ? "symbol" : typeof t7; -}; -var PRESET_COLOR_MAP = { "light-blue": "#7cd6fd", blue: "#5e64ff", violet: "#743ee2", red: "#ff5858", orange: "#ffa00a", yellow: "#feef72", green: "#28a745", "light-green": "#98d85b", purple: "#b554ff", magenta: "#ffa3ef", black: "#36114C", grey: "#bdd3e6", "light-grey": "#f0f4f7", "dark-grey": "#b8c2cc" }; -var getColor = function(t7) { - return /rgb[a]{0,1}\([\d, ]+\)/gim.test(t7) ? /\D+(\d*)\D+(\d*)\D+(\d*)/gim.exec(t7).map(function(t8, e) { - return e !== 0 ? Number(t8).toString(16) : "#"; - }).reduce(function(t8, e) { - return "" + t8 + e; - }) : PRESET_COLOR_MAP[t7] || t7; -}; -var _slicedToArray = function() { - function t7(t8, e) { - var n = [], i = true, a = false, r = void 0; - try { - for (var o, s = t8[Symbol.iterator](); !(i = (o = s.next()).done) && (n.push(o.value), !e || n.length !== e); i = true) - ; - } catch (t9) { - a = true, r = t9; - } finally { - try { - !i && s.return && s.return(); - } finally { - if (a) - throw r; - } - } - return n; - } - return function(e, n) { - if (Array.isArray(e)) - return e; - if (Symbol.iterator in Object(e)) - return t7(e, n); - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - }; -}(); -var _typeof$1 = typeof Symbol == "function" && typeof Symbol.iterator == "symbol" ? function(t7) { - return typeof t7; -} : function(t7) { - return t7 && typeof Symbol == "function" && t7.constructor === Symbol && t7 !== Symbol.prototype ? "symbol" : typeof t7; -}; -var AXIS_TICK_LENGTH = 6; -var LABEL_MARGIN = 4; -var LABEL_MAX_CHARS = 15; -var FONT_SIZE = 10; -var BASE_LINE_COLOR = "#dadada"; -var FONT_FILL = "#555b51"; -var makeOverlay = { bar: function(t7) { - var e = void 0; - t7.nodeName !== "rect" && (e = t7.getAttribute("transform"), t7 = t7.childNodes[0]); - var n = t7.cloneNode(); - return n.style.fill = "#000000", n.style.opacity = "0.4", e && n.setAttribute("transform", e), n; -}, dot: function(t7) { - var e = void 0; - t7.nodeName !== "circle" && (e = t7.getAttribute("transform"), t7 = t7.childNodes[0]); - var n = t7.cloneNode(), i = t7.getAttribute("r"), a = t7.getAttribute("fill"); - return n.setAttribute("r", parseInt(i) + DOT_OVERLAY_SIZE_INCR), n.setAttribute("fill", a), n.style.opacity = "0.6", e && n.setAttribute("transform", e), n; -}, heat_square: function(t7) { - var e = void 0; - t7.nodeName !== "circle" && (e = t7.getAttribute("transform"), t7 = t7.childNodes[0]); - var n = t7.cloneNode(), i = t7.getAttribute("r"), a = t7.getAttribute("fill"); - return n.setAttribute("r", parseInt(i) + DOT_OVERLAY_SIZE_INCR), n.setAttribute("fill", a), n.style.opacity = "0.6", e && n.setAttribute("transform", e), n; -} }; -var updateOverlay = { bar: function(t7, e) { - var n = void 0; - t7.nodeName !== "rect" && (n = t7.getAttribute("transform"), t7 = t7.childNodes[0]); - var i = ["x", "y", "width", "height"]; - Object.values(t7.attributes).filter(function(t8) { - return i.includes(t8.name) && t8.specified; - }).map(function(t8) { - e.setAttribute(t8.name, t8.nodeValue); - }), n && e.setAttribute("transform", n); -}, dot: function(t7, e) { - var n = void 0; - t7.nodeName !== "circle" && (n = t7.getAttribute("transform"), t7 = t7.childNodes[0]); - var i = ["cx", "cy"]; - Object.values(t7.attributes).filter(function(t8) { - return i.includes(t8.name) && t8.specified; - }).map(function(t8) { - e.setAttribute(t8.name, t8.nodeValue); - }), n && e.setAttribute("transform", n); -}, heat_square: function(t7, e) { - var n = void 0; - t7.nodeName !== "circle" && (n = t7.getAttribute("transform"), t7 = t7.childNodes[0]); - var i = ["cx", "cy"]; - Object.values(t7.attributes).filter(function(t8) { - return i.includes(t8.name) && t8.specified; - }).map(function(t8) { - e.setAttribute(t8.name, t8.nodeValue); - }), n && e.setAttribute("transform", n); -} }; -var _slicedToArray$2 = function() { - function t7(t8, e) { - var n = [], i = true, a = false, r = void 0; - try { - for (var o, s = t8[Symbol.iterator](); !(i = (o = s.next()).done) && (n.push(o.value), !e || n.length !== e); i = true) - ; - } catch (t9) { - a = true, r = t9; - } finally { - try { - !i && s.return && s.return(); - } finally { - if (a) - throw r; - } - } - return n; - } - return function(e, n) { - if (Array.isArray(e)) - return e; - if (Symbol.iterator in Object(e)) - return t7(e, n); - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - }; -}(); -var UNIT_ANIM_DUR = 350; -var PATH_ANIM_DUR = 350; -var MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR; -var REPLACE_ALL_NEW_DUR = 250; -var STD_EASING = "easein"; -var _slicedToArray$1 = function() { - function t7(t8, e) { - var n = [], i = true, a = false, r = void 0; - try { - for (var o, s = t8[Symbol.iterator](); !(i = (o = s.next()).done) && (n.push(o.value), !e || n.length !== e); i = true) - ; - } catch (t9) { - a = true, r = t9; - } finally { - try { - !i && s.return && s.return(); - } finally { - if (a) - throw r; - } - } - return n; - } - return function(e, n) { - if (Array.isArray(e)) - return e; - if (Symbol.iterator in Object(e)) - return t7(e, n); - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - }; -}(); -var EASING = { ease: "0.25 0.1 0.25 1", linear: "0 0 1 1", easein: "0.1 0.8 0.2 1", easeout: "0 0 0.58 1", easeinout: "0.42 0 0.58 1" }; -var CSSTEXT = ".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}"; -var _createClass$2 = function() { - function t7(t8, e) { - for (var n = 0; n < e.length; n++) { - var i = e[n]; - i.enumerable = i.enumerable || false, i.configurable = true, "value" in i && (i.writable = true), Object.defineProperty(t8, i.key, i); - } - } - return function(e, n, i) { - return n && t7(e.prototype, n), i && t7(e, i), e; - }; -}(); -var BaseChart = function() { - function t7(e, n) { - if (_classCallCheck$3(this, t7), n = deepClone(n), this.parent = typeof e == "string" ? document.querySelector(e) : e, !(this.parent instanceof HTMLElement)) - throw new Error("No `parent` element to render on was provided."); - this.rawChartArgs = n, this.title = n.title || "", this.type = n.type || "", this.realData = this.prepareData(n.data), this.data = this.prepareFirstData(this.realData), this.colors = this.validateColors(n.colors, this.type), this.config = { showTooltip: 1, showLegend: 1, isNavigable: n.isNavigable || 0, animate: n.animate !== void 0 ? n.animate : 1, truncateLegends: n.truncateLegends || 1 }, this.measures = JSON.parse(JSON.stringify(BASE_MEASURES)); - var i = this.measures; - this.setMeasures(n), this.title.length || (i.titleHeight = 0), this.config.showLegend || (i.legendHeight = 0), this.argHeight = n.height || i.baseHeight, this.state = {}, this.options = {}, this.initTimeout = INIT_CHART_UPDATE_TIMEOUT, this.config.isNavigable && (this.overlays = []), this.configure(n); - } - return _createClass$2(t7, [{ key: "prepareData", value: function(t8) { - return t8; - } }, { key: "prepareFirstData", value: function(t8) { - return t8; - } }, { key: "validateColors", value: function(t8, e) { - var n = []; - return (t8 = (t8 || []).concat(DEFAULT_COLORS[e])).forEach(function(t9) { - var e2 = getColor(t9); - isValidColor(e2) ? n.push(e2) : console.warn('"' + t9 + '" is not a valid color.'); - }), n; - } }, { key: "setMeasures", value: function() { - } }, { key: "configure", value: function() { - var t8 = this, e = this.argHeight; - this.baseHeight = e, this.height = e - getExtraHeight(this.measures), this.boundDrawFn = function() { - return t8.draw(true); - }, ResizeObserver && (this.resizeObserver = new ResizeObserver(this.boundDrawFn), this.resizeObserver.observe(this.parent)), window.addEventListener("resize", this.boundDrawFn), window.addEventListener("orientationchange", this.boundDrawFn); - } }, { key: "destroy", value: function() { - this.resizeObserver && this.resizeObserver.disconnect(), window.removeEventListener("resize", this.boundDrawFn), window.removeEventListener("orientationchange", this.boundDrawFn); - } }, { key: "setup", value: function() { - this.makeContainer(), this.updateWidth(), this.makeTooltip(), this.draw(false, true); - } }, { key: "makeContainer", value: function() { - this.parent.innerHTML = ""; - var t8 = { inside: this.parent, className: "chart-container" }; - this.independentWidth && (t8.styles = { width: this.independentWidth + "px" }), this.container = $.create("div", t8); - } }, { key: "makeTooltip", value: function() { - this.tip = new SvgTip({ parent: this.container, colors: this.colors }), this.bindTooltip(); - } }, { key: "bindTooltip", value: function() { - } }, { key: "draw", value: function() { - var t8 = this, e = arguments.length > 0 && arguments[0] !== void 0 && arguments[0], n = arguments.length > 1 && arguments[1] !== void 0 && arguments[1]; - e && isHidden(this.parent) || (this.updateWidth(), this.calc(e), this.makeChartArea(), this.setupComponents(), this.components.forEach(function(e2) { - return e2.setup(t8.drawArea); - }), this.render(this.components, false), n && (this.data = this.realData, setTimeout(function() { - t8.update(t8.data); - }, this.initTimeout)), this.renderLegend(), this.setupNavigation(n)); - } }, { key: "calc", value: function() { - } }, { key: "updateWidth", value: function() { - this.baseWidth = getElementContentWidth(this.parent), this.width = this.baseWidth - getExtraWidth(this.measures); - } }, { key: "makeChartArea", value: function() { - this.svg && this.container.removeChild(this.svg); - var t8 = this.measures; - this.svg = makeSVGContainer(this.container, "frappe-chart chart", this.baseWidth, this.baseHeight), this.svgDefs = makeSVGDefs(this.svg), this.title.length && (this.titleEL = makeText("title", t8.margins.left, t8.margins.top, this.title, { fontSize: t8.titleFontSize, fill: "#666666", dy: t8.titleFontSize })); - var e = getTopOffset(t8); - this.drawArea = makeSVGGroup(this.type + "-chart chart-draw-area", "translate(" + getLeftOffset(t8) + ", " + e + ")"), this.config.showLegend && (e += this.height + t8.paddings.bottom, this.legendArea = makeSVGGroup("chart-legend", "translate(" + getLeftOffset(t8) + ", " + e + ")")), this.title.length && this.svg.appendChild(this.titleEL), this.svg.appendChild(this.drawArea), this.config.showLegend && this.svg.appendChild(this.legendArea), this.updateTipOffset(getLeftOffset(t8), getTopOffset(t8)); - } }, { key: "updateTipOffset", value: function(t8, e) { - this.tip.offset = { x: t8, y: e }; - } }, { key: "setupComponents", value: function() { - this.components = new Map(); - } }, { key: "update", value: function(t8) { - t8 || console.error("No data to update."), this.data = this.prepareData(t8), this.calc(), this.render(this.components, this.config.animate), this.renderLegend(); - } }, { key: "render", value: function() { - var t8 = this, e = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.components, n = !(arguments.length > 1 && arguments[1] !== void 0) || arguments[1]; - this.config.isNavigable && this.overlays.map(function(t9) { - return t9.parentNode.removeChild(t9); - }); - var i = []; - e.forEach(function(t9) { - i = i.concat(t9.update(n)); - }), i.length > 0 ? (runSMILAnimation(this.container, this.svg, i), setTimeout(function() { - e.forEach(function(t9) { - return t9.make(); - }), t8.updateNav(); - }, CHART_POST_ANIMATE_TIMEOUT)) : (e.forEach(function(t9) { - return t9.make(); - }), this.updateNav()); - } }, { key: "updateNav", value: function() { - this.config.isNavigable && (this.makeOverlay(), this.bindUnits()); - } }, { key: "renderLegend", value: function() { - } }, { key: "setupNavigation", value: function() { - var t8 = this, e = arguments.length > 0 && arguments[0] !== void 0 && arguments[0]; - this.config.isNavigable && e && (this.bindOverlay(), this.keyActions = { 13: this.onEnterKey.bind(this), 37: this.onLeftArrow.bind(this), 38: this.onUpArrow.bind(this), 39: this.onRightArrow.bind(this), 40: this.onDownArrow.bind(this) }, document.addEventListener("keydown", function(e2) { - isElementInViewport(t8.container) && (e2 = e2 || window.event, t8.keyActions[e2.keyCode] && t8.keyActions[e2.keyCode]()); - })); - } }, { key: "makeOverlay", value: function() { - } }, { key: "updateOverlay", value: function() { - } }, { key: "bindOverlay", value: function() { - } }, { key: "bindUnits", value: function() { - } }, { key: "onLeftArrow", value: function() { - } }, { key: "onRightArrow", value: function() { - } }, { key: "onUpArrow", value: function() { - } }, { key: "onDownArrow", value: function() { - } }, { key: "onEnterKey", value: function() { - } }, { key: "addDataPoint", value: function() { - } }, { key: "removeDataPoint", value: function() { - } }, { key: "getDataPoint", value: function() { - } }, { key: "setCurrentDataPoint", value: function() { - } }, { key: "updateDataset", value: function() { - } }, { key: "export", value: function() { - var t8 = prepareForExport(this.svg); - downloadFile(this.title || "Chart", [t8]); - } }]), t7; -}(); -var _createClass$1 = function() { - function t7(t8, e) { - for (var n = 0; n < e.length; n++) { - var i = e[n]; - i.enumerable = i.enumerable || false, i.configurable = true, "value" in i && (i.writable = true), Object.defineProperty(t8, i.key, i); - } - } - return function(e, n, i) { - return n && t7(e.prototype, n), i && t7(e, i), e; - }; -}(); -var _get$1 = function t(e, n, i) { - e === null && (e = Function.prototype); - var a = Object.getOwnPropertyDescriptor(e, n); - if (a === void 0) { - var r = Object.getPrototypeOf(e); - return r === null ? void 0 : t(r, n, i); - } - if ("value" in a) - return a.value; - var o = a.get; - if (o !== void 0) - return o.call(i); -}; -var AggregationChart = function(t7) { - function e(t8, n) { - return _classCallCheck$2(this, e), _possibleConstructorReturn$1(this, (e.__proto__ || Object.getPrototypeOf(e)).call(this, t8, n)); - } - return _inherits$1(e, t7), _createClass$1(e, [{ key: "configure", value: function(t8) { - _get$1(e.prototype.__proto__ || Object.getPrototypeOf(e.prototype), "configure", this).call(this, t8), this.config.formatTooltipY = (t8.tooltipOptions || {}).formatTooltipY, this.config.maxSlices = t8.maxSlices || 20, this.config.maxLegendPoints = t8.maxLegendPoints || 20; - } }, { key: "calc", value: function() { - var t8 = this, e2 = this.state, n = this.config.maxSlices; - e2.sliceTotals = []; - var i = this.data.labels.map(function(e3, n2) { - var i2 = 0; - return t8.data.datasets.map(function(t9) { - i2 += t9.values[n2]; - }), [i2, e3]; - }).filter(function(t9) { - return t9[0] >= 0; - }), a = i; - if (i.length > n) { - i.sort(function(t9, e3) { - return e3[0] - t9[0]; - }), a = i.slice(0, n - 1); - var r = 0; - i.slice(n - 1).map(function(t9) { - r += t9[0]; - }), a.push([r, "Rest"]), this.colors[n - 1] = "grey"; - } - e2.labels = [], a.map(function(t9) { - e2.sliceTotals.push(round(t9[0])), e2.labels.push(t9[1]); - }), e2.grandTotal = e2.sliceTotals.reduce(function(t9, e3) { - return t9 + e3; - }, 0), this.center = { x: this.width / 2, y: this.height / 2 }; - } }, { key: "renderLegend", value: function() { - var t8 = this, e2 = this.state; - this.legendArea.textContent = "", this.legendTotals = e2.sliceTotals.slice(0, this.config.maxLegendPoints); - var n = 0, i = 0; - this.legendTotals.map(function(a, r) { - var o = 150, s = Math.floor((t8.width - getExtraWidth(t8.measures)) / o); - t8.legendTotals.length < s && (o = t8.width / t8.legendTotals.length), n > s && (n = 0, i += 20); - var l = o * n + 5, u = t8.config.truncateLegends ? truncateString(e2.labels[r], o / 10) : e2.labels[r], c = t8.config.formatTooltipY ? t8.config.formatTooltipY(a) : a, h = legendDot(l, i, 5, t8.colors[r], u + ": " + c, false); - t8.legendArea.appendChild(h), n++; - }); - } }]), e; -}(BaseChart); -var NO_OF_YEAR_MONTHS = 12; -var NO_OF_DAYS_IN_WEEK = 7; -var NO_OF_MILLIS = 1e3; -var SEC_IN_DAY = 86400; -var MONTH_NAMES = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]; -var DAY_NAMES_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; -var _slicedToArray$3 = function() { - function t7(t8, e) { - var n = [], i = true, a = false, r = void 0; - try { - for (var o, s = t8[Symbol.iterator](); !(i = (o = s.next()).done) && (n.push(o.value), !e || n.length !== e); i = true) - ; - } catch (t9) { - a = true, r = t9; - } finally { - try { - !i && s.return && s.return(); - } finally { - if (a) - throw r; - } - } - return n; - } - return function(e, n) { - if (Array.isArray(e)) - return e; - if (Symbol.iterator in Object(e)) - return t7(e, n); - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - }; -}(); -var _createClass$4 = function() { - function t7(t8, e) { - for (var n = 0; n < e.length; n++) { - var i = e[n]; - i.enumerable = i.enumerable || false, i.configurable = true, "value" in i && (i.writable = true), Object.defineProperty(t8, i.key, i); - } - } - return function(e, n, i) { - return n && t7(e.prototype, n), i && t7(e, i), e; - }; -}(); -var ChartComponent = function() { - function t7(e) { - var n = e.layerClass, i = n === void 0 ? "" : n, a = e.layerTransform, r = a === void 0 ? "" : a, o = e.constants, s = e.getData, l = e.makeElements, u = e.animateElements; - _classCallCheck$5(this, t7), this.layerTransform = r, this.constants = o, this.makeElements = l, this.getData = s, this.animateElements = u, this.store = [], this.labels = [], this.layerClass = i, this.layerClass = typeof this.layerClass == "function" ? this.layerClass() : this.layerClass, this.refresh(); - } - return _createClass$4(t7, [{ key: "refresh", value: function(t8) { - this.data = t8 || this.getData(); - } }, { key: "setup", value: function(t8) { - this.layer = makeSVGGroup(this.layerClass, this.layerTransform, t8); - } }, { key: "make", value: function() { - this.render(this.data), this.oldData = this.data; - } }, { key: "render", value: function(t8) { - var e = this; - this.store = this.makeElements(t8), this.layer.textContent = "", this.store.forEach(function(t9) { - e.layer.appendChild(t9); - }), this.labels.forEach(function(t9) { - e.layer.appendChild(t9); - }); - } }, { key: "update", value: function() { - var t8 = !(arguments.length > 0 && arguments[0] !== void 0) || arguments[0]; - this.refresh(); - var e = []; - return t8 && (e = this.animateElements(this.data) || []), e; - } }]), t7; -}(); -var componentConfigs = { donutSlices: { layerClass: "donut-slices", makeElements: function(t7) { - return t7.sliceStrings.map(function(e, n) { - var i = makePath(e, "donut-path", t7.colors[n], "none", t7.strokeWidth); - return i.style.transition = "transform .3s;", i; - }); -}, animateElements: function(t7) { - return this.store.map(function(e, n) { - return animatePathStr(e, t7.sliceStrings[n]); - }); -} }, pieSlices: { layerClass: "pie-slices", makeElements: function(t7) { - return t7.sliceStrings.map(function(e, n) { - var i = makePath(e, "pie-path", "none", t7.colors[n]); - return i.style.transition = "transform .3s;", i; - }); -}, animateElements: function(t7) { - return this.store.map(function(e, n) { - return animatePathStr(e, t7.sliceStrings[n]); - }); -} }, percentageBars: { layerClass: "percentage-bars", makeElements: function(t7) { - var e = this; - return t7.xPositions.map(function(n, i) { - return percentageBar(n, 0, t7.widths[i], e.constants.barHeight, e.constants.barDepth, t7.colors[i]); - }); -}, animateElements: function(t7) { - if (t7) - return []; -} }, yAxis: { layerClass: "y axis", makeElements: function(t7) { - var e = this; - return t7.positions.map(function(n, i) { - return yLine(n, t7.labels[i], e.constants.width, { mode: e.constants.mode, pos: e.constants.pos, shortenNumbers: e.constants.shortenNumbers }); - }); -}, animateElements: function(t7) { - var e = t7.positions, n = t7.labels, i = this.oldData.positions, a = this.oldData.labels, r = equilizeNoOfElements(i, e), o = _slicedToArray$3(r, 2); - i = o[0], e = o[1]; - var s = equilizeNoOfElements(a, n), l = _slicedToArray$3(s, 2); - return a = l[0], n = l[1], this.render({ positions: i, labels: n }), this.store.map(function(t8, n2) { - return translateHoriLine(t8, e[n2], i[n2]); - }); -} }, xAxis: { layerClass: "x axis", makeElements: function(t7) { - var e = this; - return t7.positions.map(function(n, i) { - return xLine(n, t7.calcLabels[i], e.constants.height, { mode: e.constants.mode, pos: e.constants.pos }); - }); -}, animateElements: function(t7) { - var e = t7.positions, n = t7.calcLabels, i = this.oldData.positions, a = this.oldData.calcLabels, r = equilizeNoOfElements(i, e), o = _slicedToArray$3(r, 2); - i = o[0], e = o[1]; - var s = equilizeNoOfElements(a, n), l = _slicedToArray$3(s, 2); - return a = l[0], n = l[1], this.render({ positions: i, calcLabels: n }), this.store.map(function(t8, n2) { - return translateVertLine(t8, e[n2], i[n2]); - }); -} }, yMarkers: { layerClass: "y-markers", makeElements: function(t7) { - var e = this; - return t7.map(function(t8) { - return yMarker(t8.position, t8.label, e.constants.width, { labelPos: t8.options.labelPos, mode: "span", lineType: "dashed" }); - }); -}, animateElements: function(t7) { - var e = equilizeNoOfElements(this.oldData, t7), n = _slicedToArray$3(e, 2); - this.oldData = n[0]; - var i = (t7 = n[1]).map(function(t8) { - return t8.position; - }), a = t7.map(function(t8) { - return t8.label; - }), r = t7.map(function(t8) { - return t8.options; - }), o = this.oldData.map(function(t8) { - return t8.position; - }); - return this.render(o.map(function(t8, e2) { - return { position: o[e2], label: a[e2], options: r[e2] }; - })), this.store.map(function(t8, e2) { - return translateHoriLine(t8, i[e2], o[e2]); - }); -} }, yRegions: { layerClass: "y-regions", makeElements: function(t7) { - var e = this; - return t7.map(function(t8) { - return yRegion(t8.startPos, t8.endPos, e.constants.width, t8.label, { labelPos: t8.options.labelPos }); - }); -}, animateElements: function(t7) { - var e = equilizeNoOfElements(this.oldData, t7), n = _slicedToArray$3(e, 2); - this.oldData = n[0]; - var i = (t7 = n[1]).map(function(t8) { - return t8.endPos; - }), a = t7.map(function(t8) { - return t8.label; - }), r = t7.map(function(t8) { - return t8.startPos; - }), o = t7.map(function(t8) { - return t8.options; - }), s = this.oldData.map(function(t8) { - return t8.endPos; - }), l = this.oldData.map(function(t8) { - return t8.startPos; - }); - this.render(s.map(function(t8, e2) { - return { startPos: l[e2], endPos: s[e2], label: a[e2], options: o[e2] }; - })); - var u = []; - return this.store.map(function(t8, e2) { - u = u.concat(animateRegion(t8, r[e2], i[e2], s[e2])); - }), u; -} }, heatDomain: { layerClass: function() { - return "heat-domain domain-" + this.constants.index; -}, makeElements: function(t7) { - var e = this, n = this.constants, i = n.index, a = n.colWidth, r = n.rowHeight, o = n.squareSize, s = n.radius, l = n.xTranslate, u = 0; - return this.serializedSubDomains = [], t7.cols.map(function(t8, n2) { - n2 === 1 && e.labels.push(makeText("domain-name", l, -12, getMonthName(i, true).toUpperCase(), { fontSize: 9 })), t8.map(function(t9, n3) { - if (t9.fill) { - var i2 = { "data-date": t9.yyyyMmDd, "data-value": t9.dataValue, "data-day": n3 }, a2 = heatSquare("day", l, u, o, s, t9.fill, i2); - e.serializedSubDomains.push(a2); - } - u += r; - }), u = 0, l += a; - }), this.serializedSubDomains; -}, animateElements: function(t7) { - if (t7) - return []; -} }, barGraph: { layerClass: function() { - return "dataset-units dataset-bars dataset-" + this.constants.index; -}, makeElements: function(t7) { - var e = this.constants; - return this.unitType = "bar", this.units = t7.yPositions.map(function(n, i) { - return datasetBar(t7.xPositions[i], n, t7.barWidth, e.color, t7.labels[i], i, t7.offsets[i], { zeroLine: t7.zeroLine, barsWidth: t7.barsWidth, minHeight: e.minHeight }); - }), this.units; -}, animateElements: function(t7) { - var e = t7.xPositions, n = t7.yPositions, i = t7.offsets, a = t7.labels, r = this.oldData.xPositions, o = this.oldData.yPositions, s = this.oldData.offsets, l = this.oldData.labels, u = equilizeNoOfElements(r, e), c = _slicedToArray$3(u, 2); - r = c[0], e = c[1]; - var h = equilizeNoOfElements(o, n), d = _slicedToArray$3(h, 2); - o = d[0], n = d[1]; - var f = equilizeNoOfElements(s, i), p = _slicedToArray$3(f, 2); - s = p[0], i = p[1]; - var v = equilizeNoOfElements(l, a), g = _slicedToArray$3(v, 2); - l = g[0], a = g[1], this.render({ xPositions: r, yPositions: o, offsets: s, labels: a, zeroLine: this.oldData.zeroLine, barsWidth: this.oldData.barsWidth, barWidth: this.oldData.barWidth }); - var y = []; - return this.store.map(function(a2, r2) { - y = y.concat(animateBar(a2, e[r2], n[r2], t7.barWidth, i[r2], { zeroLine: t7.zeroLine })); - }), y; -} }, lineGraph: { layerClass: function() { - return "dataset-units dataset-line dataset-" + this.constants.index; -}, makeElements: function(t7) { - var e = this.constants; - return this.unitType = "dot", this.paths = {}, e.hideLine || (this.paths = getPaths(t7.xPositions, t7.yPositions, e.color, { heatline: e.heatline, regionFill: e.regionFill, spline: e.spline }, { svgDefs: e.svgDefs, zeroLine: t7.zeroLine })), this.units = [], e.hideDots || (this.units = t7.yPositions.map(function(n, i) { - return datasetDot(t7.xPositions[i], n, t7.radius, e.color, e.valuesOverPoints ? t7.values[i] : "", i); - })), Object.values(this.paths).concat(this.units); -}, animateElements: function(t7) { - var e = t7.xPositions, n = t7.yPositions, i = t7.values, a = this.oldData.xPositions, r = this.oldData.yPositions, o = this.oldData.values, s = equilizeNoOfElements(a, e), l = _slicedToArray$3(s, 2); - a = l[0], e = l[1]; - var u = equilizeNoOfElements(r, n), c = _slicedToArray$3(u, 2); - r = c[0], n = c[1]; - var h = equilizeNoOfElements(o, i), d = _slicedToArray$3(h, 2); - o = d[0], i = d[1], this.render({ xPositions: a, yPositions: r, values: i, zeroLine: this.oldData.zeroLine, radius: this.oldData.radius }); - var f = []; - return Object.keys(this.paths).length && (f = f.concat(animatePath(this.paths, e, n, t7.zeroLine, this.constants.spline))), this.units.length && this.units.map(function(t8, i2) { - f = f.concat(animateDot(t8, e[i2], n[i2])); - }), f; -} } }; -var _createClass = function() { - function t7(t8, e) { - for (var n = 0; n < e.length; n++) { - var i = e[n]; - i.enumerable = i.enumerable || false, i.configurable = true, "value" in i && (i.writable = true), Object.defineProperty(t8, i.key, i); - } - } - return function(e, n, i) { - return n && t7(e.prototype, n), i && t7(e, i), e; - }; -}(); -var _get = function t2(e, n, i) { - e === null && (e = Function.prototype); - var a = Object.getOwnPropertyDescriptor(e, n); - if (a === void 0) { - var r = Object.getPrototypeOf(e); - return r === null ? void 0 : t2(r, n, i); - } - if ("value" in a) - return a.value; - var o = a.get; - if (o !== void 0) - return o.call(i); -}; -var PercentageChart = function(t7) { - function e(t8, n) { - _classCallCheck$1(this, e); - var i = _possibleConstructorReturn(this, (e.__proto__ || Object.getPrototypeOf(e)).call(this, t8, n)); - return i.type = "percentage", i.setup(), i; - } - return _inherits(e, t7), _createClass(e, [{ key: "setMeasures", value: function(t8) { - var e2 = this.measures; - this.barOptions = t8.barOptions || {}; - var n = this.barOptions; - n.height = n.height || PERCENTAGE_BAR_DEFAULT_HEIGHT, n.depth = n.depth || PERCENTAGE_BAR_DEFAULT_DEPTH, e2.paddings.right = 30, e2.legendHeight = 60, e2.baseHeight = 8 * (n.height + 0.5 * n.depth); - } }, { key: "setupComponents", value: function() { - var t8 = this.state, e2 = [["percentageBars", { barHeight: this.barOptions.height, barDepth: this.barOptions.depth }, function() { - return { xPositions: t8.xPositions, widths: t8.widths, colors: this.colors }; - }.bind(this)]]; - this.components = new Map(e2.map(function(t9) { - var e3 = getComponent.apply(void 0, _toConsumableArray(t9)); - return [t9[0], e3]; - })); - } }, { key: "calc", value: function() { - var t8 = this; - _get(e.prototype.__proto__ || Object.getPrototypeOf(e.prototype), "calc", this).call(this); - var n = this.state; - n.xPositions = [], n.widths = []; - var i = 0; - n.sliceTotals.map(function(e2) { - var a = t8.width * e2 / n.grandTotal; - n.widths.push(a), n.xPositions.push(i), i += a; - }); - } }, { key: "makeDataByIndex", value: function() { - } }, { key: "bindTooltip", value: function() { - var t8 = this, e2 = this.state; - this.container.addEventListener("mousemove", function(n) { - var i = t8.components.get("percentageBars").store, a = n.target; - if (i.includes(a)) { - var r = i.indexOf(a), o = getOffset(t8.container), s = getOffset(a), l = s.left - o.left + parseInt(a.getAttribute("width")) / 2, u = s.top - o.top, c = (t8.formattedLabels && t8.formattedLabels.length > 0 ? t8.formattedLabels[r] : t8.state.labels[r]) + ": ", h = e2.sliceTotals[r] / e2.grandTotal; - t8.tip.setValues(l, u, { name: c, value: (100 * h).toFixed(1) + "%" }), t8.tip.showTip(); - } - }); - } }]), e; -}(AggregationChart); -var _createClass$5 = function() { - function t7(t8, e) { - for (var n = 0; n < e.length; n++) { - var i = e[n]; - i.enumerable = i.enumerable || false, i.configurable = true, "value" in i && (i.writable = true), Object.defineProperty(t8, i.key, i); - } - } - return function(e, n, i) { - return n && t7(e.prototype, n), i && t7(e, i), e; - }; -}(); -var _get$2 = function t3(e, n, i) { - e === null && (e = Function.prototype); - var a = Object.getOwnPropertyDescriptor(e, n); - if (a === void 0) { - var r = Object.getPrototypeOf(e); - return r === null ? void 0 : t3(r, n, i); - } - if ("value" in a) - return a.value; - var o = a.get; - if (o !== void 0) - return o.call(i); -}; -var PieChart = function(t7) { - function e(t8, n) { - _classCallCheck$6(this, e); - var i = _possibleConstructorReturn$2(this, (e.__proto__ || Object.getPrototypeOf(e)).call(this, t8, n)); - return i.type = "pie", i.initTimeout = 0, i.init = 1, i.setup(), i; - } - return _inherits$2(e, t7), _createClass$5(e, [{ key: "configure", value: function(t8) { - _get$2(e.prototype.__proto__ || Object.getPrototypeOf(e.prototype), "configure", this).call(this, t8), this.mouseMove = this.mouseMove.bind(this), this.mouseLeave = this.mouseLeave.bind(this), this.hoverRadio = t8.hoverRadio || 0.1, this.config.startAngle = t8.startAngle || 0, this.clockWise = t8.clockWise || false; - } }, { key: "calc", value: function() { - var t8 = this; - _get$2(e.prototype.__proto__ || Object.getPrototypeOf(e.prototype), "calc", this).call(this); - var n = this.state; - this.radius = this.height > this.width ? this.center.x : this.center.y; - var i = this.radius, a = this.clockWise, r = n.slicesProperties || []; - n.sliceStrings = [], n.slicesProperties = []; - var o = 180 - this.config.startAngle; - n.sliceTotals.map(function(e2, s) { - var l = o, u = e2 / n.grandTotal * FULL_ANGLE, c = u > 180 ? 1 : 0, h = a ? -u : u, d = o += h, f = getPositionByAngle(l, i), p = getPositionByAngle(d, i), v = t8.init && r[s], g = void 0, y = void 0; - t8.init ? (g = v ? v.startPosition : f, y = v ? v.endPosition : f) : (g = f, y = p); - var m = u === 360 ? makeCircleStr(g, y, t8.center, t8.radius, a, c) : makeArcPathStr(g, y, t8.center, t8.radius, a, c); - n.sliceStrings.push(m), n.slicesProperties.push({ startPosition: f, endPosition: p, value: e2, total: n.grandTotal, startAngle: l, endAngle: d, angle: h }); - }), this.init = 0; - } }, { key: "setupComponents", value: function() { - var t8 = this.state, e2 = [["pieSlices", {}, function() { - return { sliceStrings: t8.sliceStrings, colors: this.colors }; - }.bind(this)]]; - this.components = new Map(e2.map(function(t9) { - var e3 = getComponent.apply(void 0, _toConsumableArray$2(t9)); - return [t9[0], e3]; - })); - } }, { key: "calTranslateByAngle", value: function(t8) { - var e2 = this.radius, n = this.hoverRadio, i = getPositionByAngle(t8.startAngle + t8.angle / 2, e2); - return "translate3d(" + i.x * n + "px," + i.y * n + "px,0)"; - } }, { key: "hoverSlice", value: function(t8, e2, n, i) { - if (t8) { - var a = this.colors[e2]; - if (n) { - transform(t8, this.calTranslateByAngle(this.state.slicesProperties[e2])), t8.style.fill = lightenDarkenColor(a, 50); - var r = getOffset(this.svg), o = i.pageX - r.left + 10, s = i.pageY - r.top - 10, l = (this.formatted_labels && this.formatted_labels.length > 0 ? this.formatted_labels[e2] : this.state.labels[e2]) + ": ", u = (100 * this.state.sliceTotals[e2] / this.state.grandTotal).toFixed(1); - this.tip.setValues(o, s, { name: l, value: u + "%" }), this.tip.showTip(); - } else - transform(t8, "translate3d(0,0,0)"), this.tip.hideTip(), t8.style.fill = a; - } - } }, { key: "bindTooltip", value: function() { - this.container.addEventListener("mousemove", this.mouseMove), this.container.addEventListener("mouseleave", this.mouseLeave); - } }, { key: "mouseMove", value: function(t8) { - var e2 = t8.target, n = this.components.get("pieSlices").store, i = this.curActiveSliceIndex, a = this.curActiveSlice; - if (n.includes(e2)) { - var r = n.indexOf(e2); - this.hoverSlice(a, i, false), this.curActiveSlice = e2, this.curActiveSliceIndex = r, this.hoverSlice(e2, r, true, t8); - } else - this.mouseLeave(); - } }, { key: "mouseLeave", value: function() { - this.hoverSlice(this.curActiveSlice, this.curActiveSliceIndex, false); - } }]), e; -}(AggregationChart); -var _slicedToArray$4 = function() { - function t7(t8, e) { - var n = [], i = true, a = false, r = void 0; - try { - for (var o, s = t8[Symbol.iterator](); !(i = (o = s.next()).done) && (n.push(o.value), !e || n.length !== e); i = true) - ; - } catch (t9) { - a = true, r = t9; - } finally { - try { - !i && s.return && s.return(); - } finally { - if (a) - throw r; - } - } - return n; - } - return function(e, n) { - if (Array.isArray(e)) - return e; - if (Symbol.iterator in Object(e)) - return t7(e, n); - throw new TypeError("Invalid attempt to destructure non-iterable instance"); - }; -}(); -var _createClass$6 = function() { - function t7(t8, e) { - for (var n = 0; n < e.length; n++) { - var i = e[n]; - i.enumerable = i.enumerable || false, i.configurable = true, "value" in i && (i.writable = true), Object.defineProperty(t8, i.key, i); - } - } - return function(e, n, i) { - return n && t7(e.prototype, n), i && t7(e, i), e; - }; -}(); -var COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE; -var ROW_HEIGHT = COL_WIDTH; -var Heatmap = function(t7) { - function e(t8, n) { - _classCallCheck$7(this, e); - var i = _possibleConstructorReturn$3(this, (e.__proto__ || Object.getPrototypeOf(e)).call(this, t8, n)); - i.type = "heatmap", i.countLabel = n.countLabel || ""; - var a = ["Sunday", "Monday"], r = a.includes(n.startSubDomain) ? n.startSubDomain : "Sunday"; - return i.startSubDomainIndex = a.indexOf(r), i.setup(), i; - } - return _inherits$3(e, t7), _createClass$6(e, [{ key: "setMeasures", value: function(t8) { - var e2 = this.measures; - this.discreteDomains = t8.discreteDomains === 0 ? 0 : 1, e2.paddings.top = 3 * ROW_HEIGHT, e2.paddings.bottom = 0, e2.legendHeight = 2 * ROW_HEIGHT, e2.baseHeight = ROW_HEIGHT * NO_OF_DAYS_IN_WEEK + getExtraHeight(e2); - var n = this.data, i = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0; - this.independentWidth = (getWeeksBetween(n.start, n.end) + i) * COL_WIDTH + getExtraWidth(e2); - } }, { key: "updateWidth", value: function() { - var t8 = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0, e2 = this.state.noOfWeeks ? this.state.noOfWeeks : 52; - this.baseWidth = (e2 + t8) * COL_WIDTH + getExtraWidth(this.measures); - } }, { key: "prepareData", value: function() { - var t8 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.data; - if (t8.start && t8.end && t8.start > t8.end) - throw new Error("Start date cannot be greater than end date."); - if (t8.start || (t8.start = new Date(), t8.start.setFullYear(t8.start.getFullYear() - 1)), t8.end || (t8.end = new Date()), t8.dataPoints = t8.dataPoints || {}, parseInt(Object.keys(t8.dataPoints)[0]) > 1e5) { - var e2 = {}; - Object.keys(t8.dataPoints).forEach(function(n) { - var i = new Date(n * NO_OF_MILLIS); - e2[getYyyyMmDd(i)] = t8.dataPoints[n]; - }), t8.dataPoints = e2; - } - return t8; - } }, { key: "calc", value: function() { - var t8 = this.state; - t8.start = clone(this.data.start), t8.end = clone(this.data.end), t8.firstWeekStart = clone(t8.start), t8.noOfWeeks = getWeeksBetween(t8.start, t8.end), t8.distribution = calcDistribution(Object.values(this.data.dataPoints), HEATMAP_DISTRIBUTION_SIZE), t8.domainConfigs = this.getDomains(); - } }, { key: "setupComponents", value: function() { - var t8 = this, e2 = this.state, n = this.discreteDomains ? 0 : 1, i = e2.domainConfigs.map(function(i2, a2) { - return ["heatDomain", { index: i2.index, colWidth: COL_WIDTH, rowHeight: ROW_HEIGHT, squareSize: HEATMAP_SQUARE_SIZE, radius: t8.rawChartArgs.radius || 0, xTranslate: e2.domainConfigs.filter(function(t9, e3) { - return e3 < a2; - }).map(function(t9) { - return t9.cols.length - n; - }).reduce(function(t9, e3) { - return t9 + e3; - }, 0) * COL_WIDTH }, function() { - return e2.domainConfigs[a2]; - }.bind(t8)]; - }); - this.components = new Map(i.map(function(t9, e3) { - var n2 = getComponent.apply(void 0, _toConsumableArray$3(t9)); - return [t9[0] + "-" + e3, n2]; - })); - var a = 0; - DAY_NAMES_SHORT.forEach(function(e3, n2) { - if ([1, 3, 5].includes(n2)) { - var i2 = makeText("subdomain-name", -COL_WIDTH / 2, a, e3, { fontSize: HEATMAP_SQUARE_SIZE, dy: 8, textAnchor: "end" }); - t8.drawArea.appendChild(i2); - } - a += ROW_HEIGHT; - }); - } }, { key: "update", value: function(t8) { - t8 || console.error("No data to update."), this.data = this.prepareData(t8), this.draw(), this.bindTooltip(); - } }, { key: "bindTooltip", value: function() { - var t8 = this; - this.container.addEventListener("mousemove", function(e2) { - t8.components.forEach(function(n) { - var i = n.store, a = e2.target; - if (i.includes(a)) { - var r = a.getAttribute("data-value"), o = a.getAttribute("data-date").split("-"), s = getMonthName(parseInt(o[1]) - 1, true), l = t8.container.getBoundingClientRect(), u = a.getBoundingClientRect(), c = parseInt(e2.target.getAttribute("width")), h = u.left - l.left + c / 2, d = u.top - l.top, f = r + " " + t8.countLabel, p = " on " + s + " " + o[0] + ", " + o[2]; - t8.tip.setValues(h, d, { name: p, value: f, valueFirst: 1 }, []), t8.tip.showTip(); - } - }); - }); - } }, { key: "renderLegend", value: function() { - var t8 = this; - this.legendArea.textContent = ""; - var e2 = 0, n = ROW_HEIGHT, i = this.rawChartArgs.radius || 0, a = makeText("subdomain-name", e2, n, "Less", { fontSize: HEATMAP_SQUARE_SIZE + 1, dy: 9 }); - e2 = 2 * COL_WIDTH + COL_WIDTH / 2, this.legendArea.appendChild(a), this.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map(function(a2, r2) { - var o = heatSquare("heatmap-legend-unit", e2 + (COL_WIDTH + 3) * r2, n, HEATMAP_SQUARE_SIZE, i, a2); - t8.legendArea.appendChild(o); - }); - var r = makeText("subdomain-name", e2 + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH / 4, n, "More", { fontSize: HEATMAP_SQUARE_SIZE + 1, dy: 9 }); - this.legendArea.appendChild(r); - } }, { key: "getDomains", value: function() { - for (var t8 = this.state, e2 = [t8.start.getMonth(), t8.start.getFullYear()], n = e2[0], i = e2[1], a = [t8.end.getMonth(), t8.end.getFullYear()], r = a[0] - n + 1 + 12 * (a[1] - i), o = [], s = clone(t8.start), l = 0; l < r; l++) { - var u = t8.end; - if (!areInSameMonth(s, t8.end)) { - var c = [s.getMonth(), s.getFullYear()]; - u = getLastDateInMonth(c[0], c[1]); - } - o.push(this.getDomainConfig(s, u)), addDays(u, 1), s = u; - } - return o; - } }, { key: "getDomainConfig", value: function(t8) { - var e2 = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "", n = [t8.getMonth(), t8.getFullYear()], i = n[0], a = n[1], r = setDayToSunday(t8), o = { index: i, cols: [] }; - addDays(e2 = clone(e2) || getLastDateInMonth(i, a), 1); - for (var s = getWeeksBetween(r, e2), l = [], u = void 0, c = 0; c < s; c++) - u = this.getCol(r, i), l.push(u), addDays(r = new Date(u[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd), 1); - return u[NO_OF_DAYS_IN_WEEK - 1].dataValue !== void 0 && (addDays(r, 1), l.push(this.getCol(r, i, true))), o.cols = l, o; - } }, { key: "getCol", value: function(t8, e2) { - for (var n = arguments.length > 2 && arguments[2] !== void 0 && arguments[2], i = this.state, a = clone(t8), r = [], o = 0; o < NO_OF_DAYS_IN_WEEK; o++, addDays(a, 1)) { - var s = {}, l = a >= i.start && a <= i.end; - n || a.getMonth() !== e2 || !l ? s.yyyyMmDd = getYyyyMmDd(a) : s = this.getSubDomainConfig(a), r.push(s); - } - return r; - } }, { key: "getSubDomainConfig", value: function(t8) { - var e2 = getYyyyMmDd(t8), n = this.data.dataPoints[e2]; - return { yyyyMmDd: e2, dataValue: n || 0, fill: this.colors[getMaxCheckpoint(n, this.state.distribution)] }; - } }]), e; -}(BaseChart); -var _createClass$7 = function() { - function t7(t8, e) { - for (var n = 0; n < e.length; n++) { - var i = e[n]; - i.enumerable = i.enumerable || false, i.configurable = true, "value" in i && (i.writable = true), Object.defineProperty(t8, i.key, i); - } - } - return function(e, n, i) { - return n && t7(e.prototype, n), i && t7(e, i), e; - }; -}(); -var _get$3 = function t4(e, n, i) { - e === null && (e = Function.prototype); - var a = Object.getOwnPropertyDescriptor(e, n); - if (a === void 0) { - var r = Object.getPrototypeOf(e); - return r === null ? void 0 : t4(r, n, i); - } - if ("value" in a) - return a.value; - var o = a.get; - if (o !== void 0) - return o.call(i); -}; -var AxisChart = function(t7) { - function e(t8, n) { - _classCallCheck$8(this, e); - var i = _possibleConstructorReturn$4(this, (e.__proto__ || Object.getPrototypeOf(e)).call(this, t8, n)); - return i.barOptions = n.barOptions || {}, i.lineOptions = n.lineOptions || {}, i.type = n.type || "line", i.init = 1, i.setup(), i; - } - return _inherits$4(e, t7), _createClass$7(e, [{ key: "setMeasures", value: function() { - this.data.datasets.length <= 1 && (this.config.showLegend = 0, this.measures.paddings.bottom = 30); - } }, { key: "configure", value: function(t8) { - _get$3(e.prototype.__proto__ || Object.getPrototypeOf(e.prototype), "configure", this).call(this, t8), t8.axisOptions = t8.axisOptions || {}, t8.tooltipOptions = t8.tooltipOptions || {}, this.config.xAxisMode = t8.axisOptions.xAxisMode || "span", this.config.yAxisMode = t8.axisOptions.yAxisMode || "span", this.config.xIsSeries = t8.axisOptions.xIsSeries || 0, this.config.shortenYAxisNumbers = t8.axisOptions.shortenYAxisNumbers || 0, this.config.formatTooltipX = t8.tooltipOptions.formatTooltipX, this.config.formatTooltipY = t8.tooltipOptions.formatTooltipY, this.config.valuesOverPoints = t8.valuesOverPoints; - } }, { key: "prepareData", value: function() { - return dataPrep(arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.data, this.type); - } }, { key: "prepareFirstData", value: function() { - return zeroDataPrep(arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.data); - } }, { key: "calc", value: function() { - var t8 = arguments.length > 0 && arguments[0] !== void 0 && arguments[0]; - this.calcXPositions(), t8 || this.calcYAxisParameters(this.getAllYValues(), this.type === "line"), this.makeDataByIndex(); - } }, { key: "calcXPositions", value: function() { - var t8 = this.state, e2 = this.data.labels; - t8.datasetLength = e2.length, t8.unitWidth = this.width / t8.datasetLength, t8.xOffset = t8.unitWidth / 2, t8.xAxis = { labels: e2, positions: e2.map(function(e3, n) { - return floatTwo(t8.xOffset + n * t8.unitWidth); - }) }; - } }, { key: "calcYAxisParameters", value: function(t8) { - var e2 = calcChartIntervals(t8, arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "false"), n = this.height / getValueRange(e2), i = getIntervalSize(e2) * n, a = this.height - getZeroIndex(e2) * i; - this.state.yAxis = { labels: e2, positions: e2.map(function(t9) { - return a - t9 * n; - }), scaleMultiplier: n, zeroLine: a }, this.calcDatasetPoints(), this.calcYExtremes(), this.calcYRegions(); - } }, { key: "calcDatasetPoints", value: function() { - var t8 = this.state, e2 = function(e3) { - return e3.map(function(e4) { - return scale(e4, t8.yAxis); - }); - }; - t8.datasets = this.data.datasets.map(function(t9, n) { - var i = t9.values, a = t9.cumulativeYs || []; - return { name: t9.name && t9.name.replace(/<|>|&/g, function(t10) { - return t10 == "&" ? "&" : t10 == "<" ? "<" : ">"; - }), index: n, chartType: t9.chartType, values: i, yPositions: e2(i), cumulativeYs: a, cumulativeYPos: e2(a) }; - }); - } }, { key: "calcYExtremes", value: function() { - var t8 = this.state; - if (this.barOptions.stacked) - return void (t8.yExtremes = t8.datasets[t8.datasets.length - 1].cumulativeYPos); - t8.yExtremes = new Array(t8.datasetLength).fill(9999), t8.datasets.map(function(e2) { - e2.yPositions.map(function(e3, n) { - e3 < t8.yExtremes[n] && (t8.yExtremes[n] = e3); - }); - }); - } }, { key: "calcYRegions", value: function() { - var t8 = this.state; - this.data.yMarkers && (this.state.yMarkers = this.data.yMarkers.map(function(e2) { - return e2.position = scale(e2.value, t8.yAxis), e2.options || (e2.options = {}), e2; - })), this.data.yRegions && (this.state.yRegions = this.data.yRegions.map(function(e2) { - return e2.startPos = scale(e2.start, t8.yAxis), e2.endPos = scale(e2.end, t8.yAxis), e2.options || (e2.options = {}), e2; - })); - } }, { key: "getAllYValues", value: function() { - var t8, e2 = this, n = "values"; - if (this.barOptions.stacked) { - n = "cumulativeYs"; - var i = new Array(this.state.datasetLength).fill(0); - this.data.datasets.map(function(t9, a2) { - var r = e2.data.datasets[a2].values; - t9[n] = i = i.map(function(t10, e3) { - return t10 + r[e3]; - }); - }); - } - var a = this.data.datasets.map(function(t9) { - return t9[n]; - }); - return this.data.yMarkers && a.push(this.data.yMarkers.map(function(t9) { - return t9.value; - })), this.data.yRegions && this.data.yRegions.map(function(t9) { - a.push([t9.end, t9.start]); - }), (t8 = []).concat.apply(t8, _toConsumableArray$5(a)); - } }, { key: "setupComponents", value: function() { - var t8 = this, e2 = [["yAxis", { mode: this.config.yAxisMode, width: this.width, shortenNumbers: this.config.shortenYAxisNumbers }, function() { - return this.state.yAxis; - }.bind(this)], ["xAxis", { mode: this.config.xAxisMode, height: this.height }, function() { - var t9 = this.state; - return t9.xAxis.calcLabels = getShortenedLabels(this.width, t9.xAxis.labels, this.config.xIsSeries), t9.xAxis; - }.bind(this)], ["yRegions", { width: this.width, pos: "right" }, function() { - return this.state.yRegions; - }.bind(this)]], n = this.state.datasets.filter(function(t9) { - return t9.chartType === "bar"; - }), i = this.state.datasets.filter(function(t9) { - return t9.chartType === "line"; - }), a = n.map(function(e3) { - var i2 = e3.index; - return ["barGraph-" + e3.index, { index: i2, color: t8.colors[i2], stacked: t8.barOptions.stacked, valuesOverPoints: t8.config.valuesOverPoints, minHeight: t8.height * MIN_BAR_PERCENT_HEIGHT }, function() { - var t9 = this.state, e4 = t9.datasets[i2], a2 = this.barOptions.stacked, r2 = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO, o2 = t9.unitWidth * (1 - r2), s2 = o2 / (a2 ? 1 : n.length), l = t9.xAxis.positions.map(function(t10) { - return t10 - o2 / 2; - }); - a2 || (l = l.map(function(t10) { - return t10 + s2 * i2; - })); - var u = new Array(t9.datasetLength).fill(""); - this.config.valuesOverPoints && (u = a2 && e4.index === t9.datasets.length - 1 ? e4.cumulativeYs : e4.values); - var c = new Array(t9.datasetLength).fill(0); - return a2 && (c = e4.yPositions.map(function(t10, n2) { - return t10 - e4.cumulativeYPos[n2]; - })), { xPositions: l, yPositions: e4.yPositions, offsets: c, labels: u, zeroLine: t9.yAxis.zeroLine, barsWidth: o2, barWidth: s2 }; - }.bind(t8)]; - }), r = i.map(function(e3) { - var n2 = e3.index; - return ["lineGraph-" + e3.index, { index: n2, color: t8.colors[n2], svgDefs: t8.svgDefs, heatline: t8.lineOptions.heatline, regionFill: t8.lineOptions.regionFill, spline: t8.lineOptions.spline, hideDots: t8.lineOptions.hideDots, hideLine: t8.lineOptions.hideLine, valuesOverPoints: t8.config.valuesOverPoints }, function() { - var t9 = this.state, e4 = t9.datasets[n2], i2 = t9.yAxis.positions[0] < t9.yAxis.zeroLine ? t9.yAxis.positions[0] : t9.yAxis.zeroLine; - return { xPositions: t9.xAxis.positions, yPositions: e4.yPositions, values: e4.values, zeroLine: i2, radius: this.lineOptions.dotSize || LINE_CHART_DOT_SIZE }; - }.bind(t8)]; - }), o = [["yMarkers", { width: this.width, pos: "right" }, function() { - return this.state.yMarkers; - }.bind(this)]]; - e2 = e2.concat(a, r, o); - var s = ["yMarkers", "yRegions"]; - this.dataUnitComponents = [], this.components = new Map(e2.filter(function(e3) { - return !s.includes(e3[0]) || t8.state[e3[0]]; - }).map(function(e3) { - var n2 = getComponent.apply(void 0, _toConsumableArray$5(e3)); - return (e3[0].includes("lineGraph") || e3[0].includes("barGraph")) && t8.dataUnitComponents.push(n2), [e3[0], n2]; - })); - } }, { key: "makeDataByIndex", value: function() { - var t8 = this; - this.dataByIndex = {}; - var e2 = this.state, n = this.config.formatTooltipX, i = this.config.formatTooltipY; - e2.xAxis.labels.map(function(a, r) { - var o = t8.state.datasets.map(function(e3, n2) { - var a2 = e3.values[r]; - return { title: e3.name, value: a2, yPos: e3.yPositions[r], color: t8.colors[n2], formatted: i ? i(a2) : a2 }; - }); - t8.dataByIndex[r] = { label: a, formattedLabel: n ? n(a) : a, xPos: e2.xAxis.positions[r], values: o, yExtreme: e2.yExtremes[r] }; - }); - } }, { key: "bindTooltip", value: function() { - var t8 = this; - this.container.addEventListener("mousemove", function(e2) { - var n = t8.measures, i = getOffset(t8.container), a = e2.pageX - i.left - getLeftOffset(n), r = e2.pageY - i.top; - r < t8.height + getTopOffset(n) && r > getTopOffset(n) ? t8.mapTooltipXPosition(a) : t8.tip.hideTip(); - }); - } }, { key: "mapTooltipXPosition", value: function(t8) { - var e2 = this.state; - if (e2.yExtremes) { - var n = getClosestInArray(t8, e2.xAxis.positions, true); - if (n >= 0) { - var i = this.dataByIndex[n]; - this.tip.setValues(i.xPos + this.tip.offset.x, i.yExtreme + this.tip.offset.y, { name: i.formattedLabel, value: "" }, i.values, n), this.tip.showTip(); - } - } - } }, { key: "renderLegend", value: function() { - var t8 = this, e2 = this.data; - e2.datasets.length > 1 && (this.legendArea.textContent = "", e2.datasets.map(function(e3, n) { - var i = AXIS_LEGEND_BAR_SIZE, a = legendBar(i * n, "0", i, t8.colors[n], e3.name, t8.config.truncateLegends); - t8.legendArea.appendChild(a); - })); - } }, { key: "makeOverlay", value: function() { - var t8 = this; - if (this.init) - return void (this.init = 0); - this.overlayGuides && this.overlayGuides.forEach(function(t9) { - var e2 = t9.overlay; - e2.parentNode.removeChild(e2); - }), this.overlayGuides = this.dataUnitComponents.map(function(t9) { - return { type: t9.unitType, overlay: void 0, units: t9.units }; - }), this.state.currentIndex === void 0 && (this.state.currentIndex = this.state.datasetLength - 1), this.overlayGuides.map(function(e2) { - var n = e2.units[t8.state.currentIndex]; - e2.overlay = makeOverlay[e2.type](n), t8.drawArea.appendChild(e2.overlay); - }); - } }, { key: "updateOverlayGuides", value: function() { - this.overlayGuides && this.overlayGuides.forEach(function(t8) { - var e2 = t8.overlay; - e2.parentNode.removeChild(e2); - }); - } }, { key: "bindOverlay", value: function() { - var t8 = this; - this.parent.addEventListener("data-select", function() { - t8.updateOverlay(); - }); - } }, { key: "bindUnits", value: function() { - var t8 = this; - this.dataUnitComponents.map(function(e2) { - e2.units.map(function(e3) { - e3.addEventListener("click", function() { - var n = e3.getAttribute("data-point-index"); - t8.setCurrentDataPoint(n); - }); - }); - }), this.tip.container.addEventListener("click", function() { - var e2 = t8.tip.container.getAttribute("data-point-index"); - t8.setCurrentDataPoint(e2); - }); - } }, { key: "updateOverlay", value: function() { - var t8 = this; - this.overlayGuides.map(function(e2) { - var n = e2.units[t8.state.currentIndex]; - updateOverlay[e2.type](n, e2.overlay); - }); - } }, { key: "onLeftArrow", value: function() { - this.setCurrentDataPoint(this.state.currentIndex - 1); - } }, { key: "onRightArrow", value: function() { - this.setCurrentDataPoint(this.state.currentIndex + 1); - } }, { key: "getDataPoint", value: function() { - var t8 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.state.currentIndex, e2 = this.state; - return { index: t8, label: e2.xAxis.labels[t8], values: e2.datasets.map(function(e3) { - return e3.values[t8]; - }) }; - } }, { key: "setCurrentDataPoint", value: function(t8) { - var e2 = this.state; - (t8 = parseInt(t8)) < 0 && (t8 = 0), t8 >= e2.xAxis.labels.length && (t8 = e2.xAxis.labels.length - 1), t8 !== e2.currentIndex && (e2.currentIndex = t8, fire(this.parent, "data-select", this.getDataPoint())); - } }, { key: "addDataPoint", value: function(t8, n) { - var i = arguments.length > 2 && arguments[2] !== void 0 ? arguments[2] : this.state.datasetLength; - _get$3(e.prototype.__proto__ || Object.getPrototypeOf(e.prototype), "addDataPoint", this).call(this, t8, n, i), this.data.labels.splice(i, 0, t8), this.data.datasets.map(function(t9, e2) { - t9.values.splice(i, 0, n[e2]); - }), this.update(this.data); - } }, { key: "removeDataPoint", value: function() { - var t8 = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : this.state.datasetLength - 1; - this.data.labels.length <= 1 || (_get$3(e.prototype.__proto__ || Object.getPrototypeOf(e.prototype), "removeDataPoint", this).call(this, t8), this.data.labels.splice(t8, 1), this.data.datasets.map(function(e2) { - e2.values.splice(t8, 1); - }), this.update(this.data)); - } }, { key: "updateDataset", value: function(t8) { - var e2 = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : 0; - this.data.datasets[e2].values = t8, this.update(this.data); - } }, { key: "updateDatasets", value: function(t8) { - this.data.datasets.map(function(e2, n) { - t8[n] && (e2.values = t8[n]); - }), this.update(this.data); - } }]), e; -}(BaseChart); -var _createClass$8 = function() { - function t7(t8, e) { - for (var n = 0; n < e.length; n++) { - var i = e[n]; - i.enumerable = i.enumerable || false, i.configurable = true, "value" in i && (i.writable = true), Object.defineProperty(t8, i.key, i); - } - } - return function(e, n, i) { - return n && t7(e.prototype, n), i && t7(e, i), e; - }; -}(); -var _get$4 = function t5(e, n, i) { - e === null && (e = Function.prototype); - var a = Object.getOwnPropertyDescriptor(e, n); - if (a === void 0) { - var r = Object.getPrototypeOf(e); - return r === null ? void 0 : t5(r, n, i); - } - if ("value" in a) - return a.value; - var o = a.get; - if (o !== void 0) - return o.call(i); -}; -var DonutChart = function(t7) { - function e(t8, n) { - _classCallCheck$9(this, e); - var i = _possibleConstructorReturn$5(this, (e.__proto__ || Object.getPrototypeOf(e)).call(this, t8, n)); - return i.type = "donut", i.initTimeout = 0, i.init = 1, i.setup(), i; - } - return _inherits$5(e, t7), _createClass$8(e, [{ key: "configure", value: function(t8) { - _get$4(e.prototype.__proto__ || Object.getPrototypeOf(e.prototype), "configure", this).call(this, t8), this.mouseMove = this.mouseMove.bind(this), this.mouseLeave = this.mouseLeave.bind(this), this.hoverRadio = t8.hoverRadio || 0.1, this.config.startAngle = t8.startAngle || 0, this.clockWise = t8.clockWise || false, this.strokeWidth = t8.strokeWidth || 30; - } }, { key: "calc", value: function() { - var t8 = this; - _get$4(e.prototype.__proto__ || Object.getPrototypeOf(e.prototype), "calc", this).call(this); - var n = this.state; - this.radius = this.height > this.width ? this.center.x - this.strokeWidth / 2 : this.center.y - this.strokeWidth / 2; - var i = this.radius, a = this.clockWise, r = n.slicesProperties || []; - n.sliceStrings = [], n.slicesProperties = []; - var o = 180 - this.config.startAngle; - n.sliceTotals.map(function(e2, s) { - var l = o, u = e2 / n.grandTotal * FULL_ANGLE, c = u > 180 ? 1 : 0, h = a ? -u : u, d = o += h, f = getPositionByAngle(l, i), p = getPositionByAngle(d, i), v = t8.init && r[s], g = void 0, y = void 0; - t8.init ? (g = v ? v.startPosition : f, y = v ? v.endPosition : f) : (g = f, y = p); - var m = u === 360 ? makeStrokeCircleStr(g, y, t8.center, t8.radius, t8.clockWise, c) : makeArcStrokePathStr(g, y, t8.center, t8.radius, t8.clockWise, c); - n.sliceStrings.push(m), n.slicesProperties.push({ startPosition: f, endPosition: p, value: e2, total: n.grandTotal, startAngle: l, endAngle: d, angle: h }); - }), this.init = 0; - } }, { key: "setupComponents", value: function() { - var t8 = this.state, e2 = [["donutSlices", {}, function() { - return { sliceStrings: t8.sliceStrings, colors: this.colors, strokeWidth: this.strokeWidth }; - }.bind(this)]]; - this.components = new Map(e2.map(function(t9) { - var e3 = getComponent.apply(void 0, _toConsumableArray$7(t9)); - return [t9[0], e3]; - })); - } }, { key: "calTranslateByAngle", value: function(t8) { - var e2 = this.radius, n = this.hoverRadio, i = getPositionByAngle(t8.startAngle + t8.angle / 2, e2); - return "translate3d(" + i.x * n + "px," + i.y * n + "px,0)"; - } }, { key: "hoverSlice", value: function(t8, e2, n, i) { - if (t8) { - var a = this.colors[e2]; - if (n) { - transform(t8, this.calTranslateByAngle(this.state.slicesProperties[e2])), t8.style.stroke = lightenDarkenColor(a, 50); - var r = getOffset(this.svg), o = i.pageX - r.left + 10, s = i.pageY - r.top - 10, l = (this.formatted_labels && this.formatted_labels.length > 0 ? this.formatted_labels[e2] : this.state.labels[e2]) + ": ", u = (100 * this.state.sliceTotals[e2] / this.state.grandTotal).toFixed(1); - this.tip.setValues(o, s, { name: l, value: u + "%" }), this.tip.showTip(); - } else - transform(t8, "translate3d(0,0,0)"), this.tip.hideTip(), t8.style.stroke = a; - } - } }, { key: "bindTooltip", value: function() { - this.container.addEventListener("mousemove", this.mouseMove), this.container.addEventListener("mouseleave", this.mouseLeave); - } }, { key: "mouseMove", value: function(t8) { - var e2 = t8.target, n = this.components.get("donutSlices").store, i = this.curActiveSliceIndex, a = this.curActiveSlice; - if (n.includes(e2)) { - var r = n.indexOf(e2); - this.hoverSlice(a, i, false), this.curActiveSlice = e2, this.curActiveSliceIndex = r, this.hoverSlice(e2, r, true, t8); - } else - this.mouseLeave(); - } }, { key: "mouseLeave", value: function() { - this.hoverSlice(this.curActiveSlice, this.curActiveSliceIndex, false); - } }]), e; -}(AggregationChart); -var chartTypes = { bar: AxisChart, line: AxisChart, percentage: PercentageChart, heatmap: Heatmap, pie: PieChart, donut: DonutChart }; -var Chart = function t6(e, n) { - return _classCallCheck(this, t6), getChartByType(n.type, e, n); -}; -export { - AxisChart, - Chart, - Heatmap, - PercentageChart, - PieChart -}; -//# sourceMappingURL=frappe-charts.js.map diff --git a/node_modules/.vite/frappe-charts.js.map b/node_modules/.vite/frappe-charts.js.map deleted file mode 100644 index 98337fd..0000000 --- a/node_modules/.vite/frappe-charts.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../frappe-charts/node_modules/style-inject/dist/style-inject.es.js", "../frappe-charts/src/js/utils/dom.js", "../frappe-charts/src/js/utils/constants.js", "../frappe-charts/src/js/utils/helpers.js", "../frappe-charts/src/js/utils/draw-utils.js", "../frappe-charts/src/js/utils/colors.js", "../frappe-charts/src/js/utils/draw.js", "../frappe-charts/src/js/utils/animate.js", "../frappe-charts/src/js/utils/animation.js", "../frappe-charts/src/js/utils/export.js", "../frappe-charts/src/js/utils/date-utils.js", "../frappe-charts/src/js/objects/ChartComponents.js", "../frappe-charts/src/js/utils/intervals.js", "../frappe-charts/src/js/utils/axis-chart-utils.js", "../frappe-charts/src/js/chart.js", "../frappe-charts/src/js/objects/SvgTip.js", "../frappe-charts/src/css/chartsCss.js", "../frappe-charts/src/js/charts/BaseChart.js", "../frappe-charts/src/js/charts/AggregationChart.js", "../frappe-charts/src/js/charts/PercentageChart.js", "../frappe-charts/src/js/charts/PieChart.js", "../frappe-charts/src/js/charts/Heatmap.js", "../frappe-charts/src/js/charts/AxisChart.js", "../frappe-charts/src/js/charts/DonutChart.js"], - "sourcesContent": ["function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n", "export function $(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\nexport function findNodeIndex(node)\n{\n\tvar i = 0;\n\twhile (node.previousSibling) {\n\t\tnode = node.previousSibling;\n\t\ti++;\n\t}\n\treturn i;\n}\n\n$.create = (tag, o) => {\n\tvar element = document.createElement(tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (i in element ) {\n\t\t\telement[i] = val;\n\t\t}\n\t\telse {\n\t\t\telement.setAttribute(i, val);\n\t\t}\n\t}\n\n\treturn element;\n};\n\nexport function getOffset(element) {\n\tlet rect = element.getBoundingClientRect();\n\treturn {\n\t\t// https://stackoverflow.com/a/7436602/6495043\n\t\t// rect.top varies with scroll, so we add whatever has been\n\t\t// scrolled to it to get absolute distance from actual page top\n\t\ttop: rect.top + (document.documentElement.scrollTop || document.body.scrollTop),\n\t\tleft: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft)\n\t};\n}\n\n// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent\n// an element's offsetParent property will return null whenever it, or any of its parents,\n// is hidden via the display style property.\nexport function isHidden(el) {\n\treturn (el.offsetParent === null);\n}\n\nexport function isElementInViewport(el) {\n\t// Although straightforward: https://stackoverflow.com/a/7557433/6495043\n\tvar rect = el.getBoundingClientRect();\n\n\treturn (\n\t\trect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */\n rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */\n\t);\n}\n\nexport function getElementContentWidth(element) {\n\tvar styles = window.getComputedStyle(element);\n\tvar padding = parseFloat(styles.paddingLeft) +\n\t\tparseFloat(styles.paddingRight);\n\n\treturn element.clientWidth - padding;\n}\n\nexport function bind(element, o){\n\tif (element) {\n\t\tfor (var event in o) {\n\t\t\tvar callback = o[event];\n\n\t\t\tevent.split(/\\s+/).forEach(function (event) {\n\t\t\t\telement.addEventListener(event, callback);\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport function unbind(element, o){\n\tif (element) {\n\t\tfor (var event in o) {\n\t\t\tvar callback = o[event];\n\n\t\t\tevent.split(/\\s+/).forEach(function(event) {\n\t\t\t\telement.removeEventListener(event, callback);\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport function fire(target, type, properties) {\n\tvar evt = document.createEvent(\"HTMLEvents\");\n\n\tevt.initEvent(type, true, true );\n\n\tfor (var j in properties) {\n\t\tevt[j] = properties[j];\n\t}\n\n\treturn target.dispatchEvent(evt);\n}\n\n// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/\nexport function forEachNode(nodeList, callback, scope) {\n\tif(!nodeList) return;\n\tfor (var i = 0; i < nodeList.length; i++) {\n\t\tcallback.call(scope, nodeList[i], i);\n\t}\n}\n\nexport function activate($parent, $child, commonClass, activeClass='active', index = -1) {\n\tlet $children = $parent.querySelectorAll(`.${commonClass}.${activeClass}`);\n\n\tforEachNode($children, (node, i) => {\n\t\tif(index >= 0 && i <= index) return;\n\t\tnode.classList.remove(activeClass);\n\t});\n\n\t$child.classList.add(activeClass);\n}\n", "export const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];\n\nexport const COMPATIBLE_CHARTS = {\n\tbar: ['line', 'scatter', 'percentage', 'pie'],\n\tline: ['scatter', 'bar', 'percentage', 'pie'],\n\tpie: ['line', 'scatter', 'percentage', 'bar'],\n\tpercentage: ['bar', 'line', 'scatter', 'pie'],\n\theatmap: []\n};\n\nexport const DATA_COLOR_DIVISIONS = {\n\tbar: 'datasets',\n\tline: 'datasets',\n\tpie: 'labels',\n\tpercentage: 'labels',\n\theatmap: HEATMAP_DISTRIBUTION_SIZE\n};\n\nexport const BASE_MEASURES = {\n\tmargins: {\n\t\ttop: 10,\n\t\tbottom: 10,\n\t\tleft: 20,\n\t\tright: 20\n\t},\n\tpaddings: {\n\t\ttop: 20,\n\t\tbottom: 40,\n\t\tleft: 30,\n\t\tright: 10\n\t},\n\n\tbaseHeight: 240,\n\ttitleHeight: 20,\n\tlegendHeight: 30,\n\n\ttitleFontSize: 12,\n};\n\nexport function getTopOffset(m) {\n\treturn m.titleHeight + m.margins.top + m.paddings.top;\n}\n\nexport function getLeftOffset(m) {\n\treturn m.margins.left + m.paddings.left;\n}\n\nexport function getExtraHeight(m) {\n\tlet totalExtraHeight = m.margins.top + m.margins.bottom\n\t\t+ m.paddings.top + m.paddings.bottom\n\t\t+ m.titleHeight + m.legendHeight;\n\treturn totalExtraHeight;\n}\n\nexport function getExtraWidth(m) {\n\tlet totalExtraWidth = m.margins.left + m.margins.right\n\t\t+ m.paddings.left + m.paddings.right;\n\n\treturn totalExtraWidth;\n}\n\nexport const INIT_CHART_UPDATE_TIMEOUT = 700;\nexport const CHART_POST_ANIMATE_TIMEOUT = 400;\n\nexport const DEFAULT_AXIS_CHART_TYPE = 'line';\nexport const AXIS_DATASET_CHART_TYPES = ['line', 'bar'];\n\nexport const AXIS_LEGEND_BAR_SIZE = 100;\n\nexport const BAR_CHART_SPACE_RATIO = 0.5;\nexport const MIN_BAR_PERCENT_HEIGHT = 0.00;\n\nexport const LINE_CHART_DOT_SIZE = 4;\nexport const DOT_OVERLAY_SIZE_INCR = 4;\n\nexport const PERCENTAGE_BAR_DEFAULT_HEIGHT = 20;\nexport const PERCENTAGE_BAR_DEFAULT_DEPTH = 2;\n\n// Fixed 5-color theme,\n// More colors are difficult to parse visually\nexport const HEATMAP_DISTRIBUTION_SIZE = 5;\n\nexport const HEATMAP_SQUARE_SIZE = 10;\nexport const HEATMAP_GUTTER_SIZE = 2;\n\nexport const DEFAULT_CHAR_WIDTH = 7;\n\nexport const TOOLTIP_POINTER_TRIANGLE_HEIGHT = 5;\n\nconst DEFAULT_CHART_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',\n\t'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey'];\nconst HEATMAP_COLORS_GREEN = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];\nexport const HEATMAP_COLORS_BLUE = ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'];\nexport const HEATMAP_COLORS_YELLOW = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];\n\nexport const DEFAULT_COLORS = {\n\tbar: DEFAULT_CHART_COLORS,\n\tline: DEFAULT_CHART_COLORS,\n\tpie: DEFAULT_CHART_COLORS,\n\tpercentage: DEFAULT_CHART_COLORS,\n\theatmap: HEATMAP_COLORS_GREEN,\n\tdonut: DEFAULT_CHART_COLORS\n};\n\n// Universal constants\nexport const ANGLE_RATIO = Math.PI / 180;\nexport const FULL_ANGLE = 360;\n", "import { ANGLE_RATIO } from './constants';\n\n/**\n * Returns the value of a number upto 2 decimal places.\n * @param {Number} d Any number\n */\nexport function floatTwo(d) {\n\treturn parseFloat(d.toFixed(2));\n}\n\n/**\n * Returns whether or not two given arrays are equal.\n * @param {Array} arr1 First array\n * @param {Array} arr2 Second array\n */\nexport function arraysEqual(arr1, arr2) {\n\tif(arr1.length !== arr2.length) return false;\n\tlet areEqual = true;\n\tarr1.map((d, i) => {\n\t\tif(arr2[i] !== d) areEqual = false;\n\t});\n\treturn areEqual;\n}\n\n/**\n * Shuffles array in place. ES6 version\n * @param {Array} array An array containing the items.\n */\nexport function shuffle(array) {\n\t// Awesomeness: https://bost.ocks.org/mike/shuffle/\n\t// https://stackoverflow.com/a/2450976/6495043\n\t// https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array?noredirect=1&lq=1\n\n\tfor (let i = array.length - 1; i > 0; i--) {\n\t\tlet j = Math.floor(Math.random() * (i + 1));\n\t\t[array[i], array[j]] = [array[j], array[i]];\n\t}\n\n\treturn array;\n}\n\n/**\n * Fill an array with extra points\n * @param {Array} array Array\n * @param {Number} count number of filler elements\n * @param {Object} element element to fill with\n * @param {Boolean} start fill at start?\n */\nexport function fillArray(array, count, element, start=false) {\n\tif(!element) {\n\t\telement = start ? array[0] : array[array.length - 1];\n\t}\n\tlet fillerArray = new Array(Math.abs(count)).fill(element);\n\tarray = start ? fillerArray.concat(array) : array.concat(fillerArray);\n\treturn array;\n}\n\n/**\n * Returns pixel width of string.\n * @param {String} string\n * @param {Number} charWidth Width of single char in pixels\n */\nexport function getStringWidth(string, charWidth) {\n\treturn (string+\"\").length * charWidth;\n}\n\nexport function bindChange(obj, getFn, setFn) {\n\treturn new Proxy(obj, {\n\t\tset: function(target, prop, value) {\n\t\t\tsetFn();\n\t\t\treturn Reflect.set(target, prop, value);\n\t\t},\n\t\tget: function(target, prop) {\n\t\t\tgetFn();\n\t\t\treturn Reflect.get(target, prop);\n\t\t}\n\t});\n}\n\n// https://stackoverflow.com/a/29325222\nexport function getRandomBias(min, max, bias, influence) {\n\tconst range = max - min;\n\tconst biasValue = range * bias + min;\n\tvar rnd = Math.random() * range + min,\t\t// random in range\n\t\tmix = Math.random() * influence;\t\t// random mixer\n\treturn rnd * (1 - mix) + biasValue * mix;\t// mix full range and bias\n}\n\nexport function getPositionByAngle(angle, radius) {\n\treturn {\n\t\tx: Math.sin(angle * ANGLE_RATIO) * radius,\n\t\ty: Math.cos(angle * ANGLE_RATIO) * radius,\n\t};\n}\n\n/**\n * Check if a number is valid for svg attributes\n * @param {object} candidate Candidate to test\n * @param {Boolean} nonNegative flag to treat negative number as invalid\n */\nexport function isValidNumber(candidate, nonNegative=false) {\n\tif (Number.isNaN(candidate)) return false;\n\telse if (candidate === undefined) return false;\n\telse if (!Number.isFinite(candidate)) return false;\n\telse if (nonNegative && candidate < 0) return false;\n\telse return true;\n}\n\n/**\n * Round a number to the closes precision, max max precision 4\n * @param {Number} d Any Number\n */\nexport function round(d) {\n\t// https://floating-point-gui.de/\n\t// https://www.jacklmoore.com/notes/rounding-in-javascript/\n\treturn Number(Math.round(d + 'e4') + 'e-4');\n}\n\n/**\n * Creates a deep clone of an object\n * @param {Object} candidate Any Object\n */\n export function deepClone(candidate) {\n\tlet cloned, value, key;\n \n\tif (candidate instanceof Date) {\n\t return new Date(candidate.getTime());\n\t}\n \n\tif (typeof candidate !== \"object\" || candidate === null) {\n\t return candidate;\n\t}\n \n\tcloned = Array.isArray(candidate) ? [] : {};\n \n\tfor (key in candidate) {\n\t value = candidate[key];\n \n\t cloned[key] = deepClone(value);\n\t}\n \n\treturn cloned;\n }", "import { fillArray } from './helpers';\n\nexport function getBarHeightAndYAttr(yTop, zeroLine) {\n\tlet height, y;\n\tif (yTop <= zeroLine) {\n\t\theight = zeroLine - yTop;\n\t\ty = yTop;\n\t} else {\n\t\theight = yTop - zeroLine;\n\t\ty = zeroLine;\n\t}\n\n\treturn [height, y];\n}\n\nexport function equilizeNoOfElements(array1, array2,\n\textraCount = array2.length - array1.length) {\n\n\t// Doesn't work if either has zero elements.\n\tif(extraCount > 0) {\n\t\tarray1 = fillArray(array1, extraCount);\n\t} else {\n\t\tarray2 = fillArray(array2, extraCount);\n\t}\n\treturn [array1, array2];\n}\n\nexport function truncateString(txt, len) {\n\tif (!txt) {\n\t\treturn;\n\t}\n\tif (txt.length > len) {\n\t\treturn txt.slice(0, len-3) + '...';\n\t} else {\n\t\treturn txt;\n\t}\n}\n\nexport function shortenLargeNumber(label) {\n\tlet number;\n\tif (typeof label === 'number') number = label;\n\telse if (typeof label === 'string') {\n\t\tnumber = Number(label);\n\t\tif (Number.isNaN(number)) return label;\n\t}\n\n\t// Using absolute since log wont work for negative numbers\n\tlet p = Math.floor(Math.log10(Math.abs(number)));\n\tif (p <= 2) return number; // Return as is for a 3 digit number of less\n\tlet\tl = Math.floor(p / 3);\n\tlet shortened = (Math.pow(10, p - l * 3) * +(number / Math.pow(10, p)).toFixed(1));\n\n\t// Correct for floating point error upto 2 decimal places\n\treturn Math.round(shortened*100)/100 + ' ' + ['', 'K', 'M', 'B', 'T'][l];\n}\n\n// cubic bezier curve calculation (from example by Fran\u00E7ois Romain)\nexport function getSplineCurvePointsStr(xList, yList) {\n\n\tlet points=[];\n\tfor(let i=0;i {\n\t\tlet lengthX = pointB[0] - pointA[0];\n\t\tlet lengthY = pointB[1] - pointA[1];\n\t\treturn {\n\t\t\tlength: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),\n\t\t\tangle: Math.atan2(lengthY, lengthX)\n\t\t};\n\t};\n \n\tlet controlPoint = (current, previous, next, reverse) => {\n\t\tlet p = previous || current;\n\t\tlet n = next || current;\n\t\tlet o = line(p, n);\n\t\tlet angle = o.angle + (reverse ? Math.PI : 0);\n\t\tlet length = o.length * smoothing;\n\t\tlet x = current[0] + Math.cos(angle) * length;\n\t\tlet y = current[1] + Math.sin(angle) * length;\n\t\treturn [x, y];\n\t};\n \n\tlet bezierCommand = (point, i, a) => {\n\t\tlet cps = controlPoint(a[i - 1], a[i - 2], point);\n\t\tlet cpe = controlPoint(point, a[i - 1], a[i + 1], true);\n\t\treturn `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`;\n\t};\n \n\tlet pointStr = (points, command) => {\n\t\treturn points.reduce((acc, point, i, a) => i === 0\n\t\t\t? `${point[0]},${point[1]}`\n\t\t\t: `${acc} ${command(point, i, a)}`, '');\n\t};\n \n\treturn pointStr(points, bezierCommand);\n}\n", "const PRESET_COLOR_MAP = {\n\t'light-blue': '#7cd6fd',\n\t'blue': '#5e64ff',\n\t'violet': '#743ee2',\n\t'red': '#ff5858',\n\t'orange': '#ffa00a',\n\t'yellow': '#feef72',\n\t'green': '#28a745',\n\t'light-green': '#98d85b',\n\t'purple': '#b554ff',\n\t'magenta': '#ffa3ef',\n\t'black': '#36114C',\n\t'grey': '#bdd3e6',\n\t'light-grey': '#f0f4f7',\n\t'dark-grey': '#b8c2cc'\n};\n\nfunction limitColor(r){\n\tif (r > 255) return 255;\n\telse if (r < 0) return 0;\n\treturn r;\n}\n\nexport function lightenDarkenColor(color, amt) {\n\tlet col = getColor(color);\n\tlet usePound = false;\n\tif (col[0] == \"#\") {\n\t\tcol = col.slice(1);\n\t\tusePound = true;\n\t}\n\tlet num = parseInt(col,16);\n\tlet r = limitColor((num >> 16) + amt);\n\tlet b = limitColor(((num >> 8) & 0x00FF) + amt);\n\tlet g = limitColor((num & 0x0000FF) + amt);\n\treturn (usePound?\"#\":\"\") + (g | (b << 8) | (r << 16)).toString(16);\n}\n\nexport function isValidColor(string) {\n\t// https://stackoverflow.com/a/32685393\n\tlet HEX_RE = /(^\\s*)(#)((?:[A-Fa-f0-9]{3}){1,2})$/i;\n\tlet RGB_RE = /(^\\s*)(rgb|hsl)(a?)[(]\\s*([\\d.]+\\s*%?)\\s*,\\s*([\\d.]+\\s*%?)\\s*,\\s*([\\d.]+\\s*%?)\\s*(?:,\\s*([\\d.]+)\\s*)?[)]$/i;\n\treturn HEX_RE.test(string) || RGB_RE.test(string);\n}\n\nexport const getColor = (color) => {\n\t// When RGB color, convert to hexadecimal (alpha value is omitted)\n\tif((/rgb[a]{0,1}\\([\\d, ]+\\)/gim).test(color)) {\n\t\treturn (/\\D+(\\d*)\\D+(\\d*)\\D+(\\d*)/gim).exec(color)\n\t\t\t.map((x, i) => (i !== 0 ? Number(x).toString(16) : '#'))\n\t\t\t.reduce((c, ch) => `${c}${ch}`);\n\t}\n\treturn PRESET_COLOR_MAP[color] || color;\n};\n", "import { getBarHeightAndYAttr, truncateString, shortenLargeNumber, getSplineCurvePointsStr } from './draw-utils';\nimport { getStringWidth, isValidNumber } from './helpers';\nimport { DOT_OVERLAY_SIZE_INCR, PERCENTAGE_BAR_DEFAULT_DEPTH } from './constants';\nimport { lightenDarkenColor } from './colors';\n\nexport const AXIS_TICK_LENGTH = 6;\nconst LABEL_MARGIN = 4;\nconst LABEL_MAX_CHARS = 15;\nexport const FONT_SIZE = 10;\nconst BASE_LINE_COLOR = '#dadada';\nconst FONT_FILL = '#555b51';\n\nfunction $(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\nexport function createSVG(tag, o) {\n\tvar element = document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tif(i === \"className\") { i = \"class\"; }\n\t\t\tif(i === \"innerHTML\") {\n\t\t\t\telement['textContent'] = val;\n\t\t\t} else {\n\t\t\t\telement.setAttribute(i, val);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n}\n\nfunction renderVerticalGradient(svgDefElem, gradientId) {\n\treturn createSVG('linearGradient', {\n\t\tinside: svgDefElem,\n\t\tid: gradientId,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: 0,\n\t\ty2: 1\n\t});\n}\n\nfunction setGradientStop(gradElem, offset, color, opacity) {\n\treturn createSVG('stop', {\n\t\t'inside': gradElem,\n\t\t'style': `stop-color: ${color}`,\n\t\t'offset': offset,\n\t\t'stop-opacity': opacity\n\t});\n}\n\nexport function makeSVGContainer(parent, className, width, height) {\n\treturn createSVG('svg', {\n\t\tclassName: className,\n\t\tinside: parent,\n\t\twidth: width,\n\t\theight: height\n\t});\n}\n\nexport function makeSVGDefs(svgContainer) {\n\treturn createSVG('defs', {\n\t\tinside: svgContainer,\n\t});\n}\n\nexport function makeSVGGroup(className, transform='', parent=undefined) {\n\tlet args = {\n\t\tclassName: className,\n\t\ttransform: transform\n\t};\n\tif(parent) args.inside = parent;\n\treturn createSVG('g', args);\n}\n\nexport function wrapInSVGGroup(elements, className='') {\n\tlet g = createSVG('g', {\n\t\tclassName: className\n\t});\n\telements.forEach(e => g.appendChild(e));\n\treturn g;\n}\n\nexport function makePath(pathStr, className='', stroke='none', fill='none', strokeWidth=2) {\n\treturn createSVG('path', {\n\t\tclassName: className,\n\t\td: pathStr,\n\t\tstyles: {\n\t\t\tstroke: stroke,\n\t\t\tfill: fill,\n\t\t\t'stroke-width': strokeWidth\n\t\t}\n\t});\n}\n\nexport function makeArcPathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];\n\treturn `M${center.x} ${center.y}\n\t\tL${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY} z`;\n}\n\nexport function makeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, center.y * 2, center.y + endPosition.y];\n\treturn `M${center.x} ${center.y}\n\t\tL${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${midArc} z\n\t\tL${arcStartX} ${midArc}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY} z`;\n}\n\nexport function makeArcStrokePathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];\n\n\treturn `M${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY}`;\n}\n\nexport function makeStrokeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, radius * 2 + arcStartY, center.y + startPosition.y];\n\n\treturn `M${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${midArc}\n\t\tM${arcStartX} ${midArc}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY}`;\n}\n\nexport function makeGradient(svgDefElem, color, lighter = false) {\n\tlet gradientId ='path-fill-gradient' + '-' + color + '-' +(lighter ? 'lighter' : 'default');\n\tlet gradientDef = renderVerticalGradient(svgDefElem, gradientId);\n\tlet opacities = [1, 0.6, 0.2];\n\tif(lighter) {\n\t\topacities = [0.4, 0.2, 0];\n\t}\n\n\tsetGradientStop(gradientDef, \"0%\", color, opacities[0]);\n\tsetGradientStop(gradientDef, \"50%\", color, opacities[1]);\n\tsetGradientStop(gradientDef, \"100%\", color, opacities[2]);\n\n\treturn gradientId;\n}\n\nexport function percentageBar(x, y, width, height,\n\tdepth=PERCENTAGE_BAR_DEFAULT_DEPTH, fill='none') {\n\n\tlet args = {\n\t\tclassName: 'percentage-bar',\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height,\n\t\tfill: fill,\n\t\tstyles: {\n\t\t\t'stroke': lightenDarkenColor(fill, -25),\n\t\t\t// Diabolically good: https://stackoverflow.com/a/9000859\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray\n\t\t\t'stroke-dasharray': `0, ${height + width}, ${width}, ${height}`,\n\t\t\t'stroke-width': depth\n\t\t},\n\t};\n\n\treturn createSVG(\"rect\", args);\n}\n\nexport function heatSquare(className, x, y, size, radius, fill='none', data={}) {\n\tlet args = {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: size,\n\t\theight: size,\n\t\trx: radius,\n\t\tfill: fill\n\t};\n\n\tObject.keys(data).map(key => {\n\t\targs[key] = data[key];\n\t});\n\n\treturn createSVG(\"rect\", args);\n}\n\nexport function legendBar(x, y, size, fill='none', label, truncate=false) {\n\tlabel = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;\n\n\tlet args = {\n\t\tclassName: 'legend-bar',\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: size,\n\t\theight: '2px',\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE * 2) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"rect\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nexport function legendDot(x, y, size, fill='none', label, truncate=false) {\n\tlabel = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;\n\n\tlet args = {\n\t\tclassName: 'legend-dot',\n\t\tcx: 0,\n\t\tcy: 0,\n\t\tr: size,\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdx: (FONT_SIZE) + 'px',\n\t\tdy: (FONT_SIZE/3) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"circle\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nexport function makeText(className, x, y, content, options = {}) {\n\tlet fontSize = options.fontSize || FONT_SIZE;\n\tlet dy = options.dy !== undefined ? options.dy : (fontSize / 2);\n\tlet fill = options.fill || FONT_FILL;\n\tlet textAnchor = options.textAnchor || 'start';\n\treturn createSVG('text', {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\tdy: dy + 'px',\n\t\t'font-size': fontSize + 'px',\n\t\tfill: fill,\n\t\t'text-anchor': textAnchor,\n\t\tinnerHTML: content\n\t});\n}\n\nfunction makeVertLine(x, label, y1, y2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tlet l = createSVG('line', {\n\t\tclassName: 'line-vertical ' + options.className,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: y1,\n\t\ty2: y2,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: 0,\n\t\ty: y1 > y2 ? y1 + LABEL_MARGIN : y1 - LABEL_MARGIN - FONT_SIZE,\n\t\tdy: FONT_SIZE + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'middle',\n\t\tinnerHTML: label + \"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(${ x }, 0)`\n\t});\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nfunction makeHoriLine(y, label, x1, x2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.lineType) options.lineType = '';\n\tif (options.shortenNumbers) label = shortenLargeNumber(label);\n\n\tlet className = 'line-horizontal ' + options.className +\n\t\t(options.lineType === \"dashed\" ? \"dashed\": \"\");\n\n\tlet l = createSVG('line', {\n\t\tclassName: className,\n\t\tx1: x1,\n\t\tx2: x2,\n\t\ty1: 0,\n\t\ty2: 0,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: x1 < x2 ? x1 - LABEL_MARGIN : x1 + LABEL_MARGIN,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / 2 - 2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': x1 < x2 ? 'end' : 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(0, ${y})`,\n\t\t'stroke-opacity': 1\n\t});\n\n\tif(text === 0 || text === '0') {\n\t\tline.style.stroke = \"rgba(27, 31, 35, 0.6)\";\n\t}\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nexport function yLine(y, label, width, options={}) {\n\tif (!isValidNumber(y)) y = 0;\n\n\tif(!options.pos) options.pos = 'left';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\tlet x1 = -1 * AXIS_TICK_LENGTH;\n\tlet x2 = options.mode === 'span' ? width + AXIS_TICK_LENGTH : 0;\n\n\tif(options.mode === 'tick' && options.pos === 'right') {\n\t\tx1 = width + AXIS_TICK_LENGTH;\n\t\tx2 = width;\n\t}\n\n\t// let offset = options.pos === 'left' ? -1 * options.offset : options.offset;\n\n\tx1 += options.offset;\n\tx2 += options.offset;\n\n\treturn makeHoriLine(y, label, x1, x2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType,\n\t\tshortenNumbers: options.shortenNumbers\n\t});\n}\n\nexport function xLine(x, label, height, options={}) {\n\tif (!isValidNumber(x)) x = 0;\n\n\tif(!options.pos) options.pos = 'bottom';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\t// Draw X axis line in span/tick mode with optional label\n\t// \ty2(span)\n\t// \t\t\t\t\t\t|\n\t// \t\t\t\t\t\t|\n\t//\t\t\t\tx line\t|\n\t//\t\t\t\t\t\t|\n\t// \t\t\t\t\t \t|\n\t// ---------------------+-- y2(tick)\n\t//\t\t\t\t\t\t|\n\t//\t\t\t\t\t\t\ty1\n\n\tlet y1 = height + AXIS_TICK_LENGTH;\n\tlet y2 = options.mode === 'span' ? -1 * AXIS_TICK_LENGTH : height;\n\n\tif(options.mode === 'tick' && options.pos === 'top') {\n\t\t// top axis ticks\n\t\ty1 = -1 * AXIS_TICK_LENGTH;\n\t\ty2 = 0;\n\t}\n\n\treturn makeVertLine(x, label, y1, y2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType\n\t});\n}\n\nexport function yMarker(y, label, width, options={}) {\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label, 5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = makeHoriLine(y, '', 0, width, {\n\t\tstroke: options.stroke || BASE_LINE_COLOR,\n\t\tclassName: options.className || '',\n\t\tlineType: options.lineType\n\t});\n\n\tline.appendChild(labelSvg);\n\n\treturn line;\n}\n\nexport function yRegion(y1, y2, width, label, options={}) {\n\t// return a group\n\tlet height = y1 - y2;\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`, // remove class\n\t\tstyles: {\n\t\t\tfill: `rgba(228, 234, 239, 0.49)`,\n\t\t\tstroke: BASE_LINE_COLOR,\n\t\t\t'stroke-dasharray': `${width}, ${height}`\n\t\t},\n\t\t// 'data-point-index': index,\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label+\"\", 4.5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet region = createSVG('g', {\n\t\ttransform: `translate(0, ${y2})`\n\t});\n\n\tregion.appendChild(rect);\n\tregion.appendChild(labelSvg);\n\n\treturn region;\n}\n\nexport function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\n\tif(height === 0) {\n\t\theight = meta.minHeight;\n\t\ty -= meta.minHeight;\n\t}\n\n\t// Preprocess numbers to avoid svg building errors\n\tif (!isValidNumber(x)) x = 0;\n\tif (!isValidNumber(y)) y = 0;\n\tif (!isValidNumber(height, true)) height = 0;\n\tif (!isValidNumber(width, true)) width = 0;\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`,\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn rect;\n\t} else {\n\t\trect.setAttribute('y', 0);\n\t\trect.setAttribute('x', 0);\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: width/2,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(rect);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nexport function datasetDot(x, y, radius, color, label='', index=0) {\n\tlet dot = createSVG('circle', {\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tcx: x,\n\t\tcy: y,\n\t\tr: radius\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn dot;\n\t} else {\n\t\tdot.setAttribute('cy', 0);\n\t\tdot.setAttribute('cx', 0);\n\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1 - radius) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(dot);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nexport function getPaths(xList, yList, color, options={}, meta={}) {\n\tlet pointsList = yList.map((y, i) => (xList[i] + ',' + y));\n\tlet pointsStr = pointsList.join(\"L\");\n\n\t// Spline\n\tif (options.spline)\n\t\tpointsStr = getSplineCurvePointsStr(xList, yList);\n\n\tlet path = makePath(\"M\"+pointsStr, 'line-graph-path', color);\n\n\t// HeatLine\n\tif(options.heatline) {\n\t\tlet gradient_id = makeGradient(meta.svgDefs, color);\n\t\tpath.style.stroke = `url(#${gradient_id})`;\n\t}\n\n\tlet paths = {\n\t\tpath: path\n\t};\n\n\t// Region\n\tif(options.regionFill) {\n\t\tlet gradient_id_region = makeGradient(meta.svgDefs, color, true);\n\n\t\tlet pathStr = \"M\" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`;\n\t\tpaths.region = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`);\n\t}\n\n\treturn paths;\n}\n\nexport let makeOverlay = {\n\t'bar': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\toverlay.style.fill = '#000000';\n\t\toverlay.style.opacity = '0.4';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'dot': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'heat_square': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t}\n};\n\nexport let updateOverlay = {\n\t'bar': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['x', 'y', 'width', 'height'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'dot': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'heat_square': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n};\n", "import { getBarHeightAndYAttr, getSplineCurvePointsStr } from './draw-utils';\n\nexport const UNIT_ANIM_DUR = 350;\nexport const PATH_ANIM_DUR = 350;\nexport const MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR;\nexport const REPLACE_ALL_NEW_DUR = 250;\n\nexport const STD_EASING = 'easein';\n\nexport function translate(unit, oldCoord, newCoord, duration) {\n\tlet old = typeof oldCoord === 'string' ? oldCoord : oldCoord.join(', ');\n\treturn [\n\t\tunit,\n\t\t{transform: newCoord.join(', ')},\n\t\tduration,\n\t\tSTD_EASING,\n\t\t\"translate\",\n\t\t{transform: old}\n\t];\n}\n\nexport function translateVertLine(xLine, newX, oldX) {\n\treturn translate(xLine, [oldX, 0], [newX, 0], MARKER_LINE_ANIM_DUR);\n}\n\nexport function translateHoriLine(yLine, newY, oldY) {\n\treturn translate(yLine, [0, oldY], [0, newY], MARKER_LINE_ANIM_DUR);\n}\n\nexport function animateRegion(rectGroup, newY1, newY2, oldY2) {\n\tlet newHeight = newY1 - newY2;\n\tlet rect = rectGroup.childNodes[0];\n\tlet width = rect.getAttribute(\"width\");\n\tlet rectAnim = [\n\t\trect,\n\t\t{ height: newHeight, 'stroke-dasharray': `${width}, ${newHeight}` },\n\t\tMARKER_LINE_ANIM_DUR,\n\t\tSTD_EASING\n\t];\n\n\tlet groupAnim = translate(rectGroup, [0, oldY2], [0, newY2], MARKER_LINE_ANIM_DUR);\n\treturn [rectAnim, groupAnim];\n}\n\nexport function animateBar(bar, x, yTop, width, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\tif(bar.nodeName !== 'rect') {\n\t\tlet rect = bar.childNodes[0];\n\t\tlet rectAnim = [\n\t\t\trect,\n\t\t\t{width: width, height: height},\n\t\t\tUNIT_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\n\t\tlet oldCoordStr = bar.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(bar, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [rectAnim, groupAnim];\n\t} else {\n\t\treturn [[bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nexport function animateDot(dot, x, y) {\n\tif(dot.nodeName !== 'circle') {\n\t\tlet oldCoordStr = dot.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(dot, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [groupAnim];\n\t} else {\n\t\treturn [[dot, {cx: x, cy: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nexport function animatePath(paths, newXList, newYList, zeroLine, spline) {\n\tlet pathComponents = [];\n\tlet pointsStr = newYList.map((y, i) => (newXList[i] + ',' + y)).join(\"L\");\n\n\tif (spline)\n\t\tpointsStr = getSplineCurvePointsStr(newXList, newYList);\n\n\tconst animPath = [paths.path, {d:\"M\" + pointsStr}, PATH_ANIM_DUR, STD_EASING];\n\tpathComponents.push(animPath);\n\n\tif(paths.region) {\n\t\tlet regStartPt = `${newXList[0]},${zeroLine}L`;\n\t\tlet regEndPt = `L${newXList.slice(-1)[0]}, ${zeroLine}`;\n\n\t\tconst animRegion = [\n\t\t\tpaths.region,\n\t\t\t{d:\"M\" + regStartPt + pointsStr + regEndPt},\n\t\t\tPATH_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\t\tpathComponents.push(animRegion);\n\t}\n\n\treturn pathComponents;\n}\n\nexport function animatePathStr(oldPath, pathStr) {\n\treturn [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING];\n}\n", "// Leveraging SMIL Animations\n\nimport { REPLACE_ALL_NEW_DUR } from './animate';\n\nconst EASING = {\n\tease: \"0.25 0.1 0.25 1\",\n\tlinear: \"0 0 1 1\",\n\t// easein: \"0.42 0 1 1\",\n\teasein: \"0.1 0.8 0.2 1\",\n\teaseout: \"0 0 0.58 1\",\n\teaseinout: \"0.42 0 0.58 1\"\n};\n\nfunction animateSVGElement(element, props, dur, easingType=\"linear\", type=undefined, oldValues={}) {\n\n\tlet animElement = element.cloneNode(true);\n\tlet newElement = element.cloneNode(true);\n\n\tfor(var attributeName in props) {\n\t\tlet animateElement;\n\t\tif(attributeName === 'transform') {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animateTransform\");\n\t\t} else {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animate\");\n\t\t}\n\t\tlet currentValue = oldValues[attributeName] || element.getAttribute(attributeName);\n\t\tlet value = props[attributeName];\n\n\t\tlet animAttr = {\n\t\t\tattributeName: attributeName,\n\t\t\tfrom: currentValue,\n\t\t\tto: value,\n\t\t\tbegin: \"0s\",\n\t\t\tdur: dur/1000 + \"s\",\n\t\t\tvalues: currentValue + \";\" + value,\n\t\t\tkeySplines: EASING[easingType],\n\t\t\tkeyTimes: \"0;1\",\n\t\t\tcalcMode: \"spline\",\n\t\t\tfill: 'freeze'\n\t\t};\n\n\t\tif(type) {\n\t\t\tanimAttr[\"type\"] = type;\n\t\t}\n\n\t\tfor (var i in animAttr) {\n\t\t\tanimateElement.setAttribute(i, animAttr[i]);\n\t\t}\n\n\t\tanimElement.appendChild(animateElement);\n\n\t\tif(type) {\n\t\t\tnewElement.setAttribute(attributeName, `translate(${value})`);\n\t\t} else {\n\t\t\tnewElement.setAttribute(attributeName, value);\n\t\t}\n\t}\n\n\treturn [animElement, newElement];\n}\n\nexport function transform(element, style) { // eslint-disable-line no-unused-vars\n\telement.style.transform = style;\n\telement.style.webkitTransform = style;\n\telement.style.msTransform = style;\n\telement.style.mozTransform = style;\n\telement.style.oTransform = style;\n}\n\nfunction animateSVG(svgContainer, elements) {\n\tlet newElements = [];\n\tlet animElements = [];\n\n\telements.map(element => {\n\t\tlet unit = element[0];\n\t\tlet parent = unit.parentNode;\n\n\t\tlet animElement, newElement;\n\n\t\telement[0] = unit;\n\t\t[animElement, newElement] = animateSVGElement(...element);\n\n\t\tnewElements.push(newElement);\n\t\tanimElements.push([animElement, parent]);\n\t\t\n\t\tif (parent) {\n\t\t\tparent.replaceChild(animElement, unit);\n\t\t}\n\t});\n\n\tlet animSvg = svgContainer.cloneNode(true);\n\n\tanimElements.map((animElement, i) => {\n\t\tif (animElement[1]) {\n\t\t\tanimElement[1].replaceChild(newElements[i], animElement[0]);\n\t\t\telements[i][0] = newElements[i];\n\t\t}\n\t});\n\n\treturn animSvg;\n}\n\nexport function runSMILAnimation(parent, svgElement, elementsToAnimate) {\n\tif(elementsToAnimate.length === 0) return;\n\n\tlet animSvgElement = animateSVG(svgElement, elementsToAnimate);\n\tif(svgElement.parentNode == parent) {\n\t\tparent.removeChild(svgElement);\n\t\tparent.appendChild(animSvgElement);\n\n\t}\n\n\t// Replace the new svgElement (data has already been replaced)\n\tsetTimeout(() => {\n\t\tif(animSvgElement.parentNode == parent) {\n\t\t\tparent.removeChild(animSvgElement);\n\t\t\tparent.appendChild(svgElement);\n\t\t}\n\t}, REPLACE_ALL_NEW_DUR);\n}\n", "import { $ } from '../utils/dom';\nimport { CSSTEXT } from '../../css/chartsCss';\n\nexport function downloadFile(filename, data) {\n\tvar a = document.createElement('a');\n\ta.style = \"display: none\";\n\tvar blob = new Blob(data, {type: \"image/svg+xml; charset=utf-8\"});\n\tvar url = window.URL.createObjectURL(blob);\n\ta.href = url;\n\ta.download = filename;\n\tdocument.body.appendChild(a);\n\ta.click();\n\tsetTimeout(function(){\n\t\tdocument.body.removeChild(a);\n\t\twindow.URL.revokeObjectURL(url);\n\t}, 300);\n}\n\nexport function prepareForExport(svg) {\n\tlet clone = svg.cloneNode(true);\n\tclone.classList.add('chart-container');\n\tclone.setAttribute('xmlns', \"http://www.w3.org/2000/svg\");\n\tclone.setAttribute('xmlns:xlink', \"http://www.w3.org/1999/xlink\");\n\tlet styleEl = $.create('style', {\n\t\t'innerHTML': CSSTEXT\n\t});\n\tclone.insertBefore(styleEl, clone.firstChild);\n\n\tlet container = $.create('div');\n\tcontainer.appendChild(clone);\n\n\treturn container.innerHTML;\n}\n", "// Playing around with dates\n\nexport const NO_OF_YEAR_MONTHS = 12;\nexport const NO_OF_DAYS_IN_WEEK = 7;\nexport const DAYS_IN_YEAR = 375;\nexport const NO_OF_MILLIS = 1000;\nexport const SEC_IN_DAY = 86400;\n\nexport const MONTH_NAMES = [\"January\", \"February\", \"March\", \"April\", \"May\",\n\t\"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"];\nexport const MONTH_NAMES_SHORT = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n\t\"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n\nexport const DAY_NAMES_SHORT = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\nexport const DAY_NAMES = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\",\n\t\"Thursday\", \"Friday\", \"Saturday\"];\n\n// https://stackoverflow.com/a/11252167/6495043\nfunction treatAsUtc(date) {\n\tlet result = new Date(date);\n\tresult.setMinutes(result.getMinutes() - result.getTimezoneOffset());\n\treturn result;\n}\n\nexport function getYyyyMmDd(date) {\n\tlet dd = date.getDate();\n\tlet mm = date.getMonth() + 1; // getMonth() is zero-based\n\treturn [\n\t\tdate.getFullYear(),\n\t\t(mm>9 ? '' : '0') + mm,\n\t\t(dd>9 ? '' : '0') + dd\n\t].join('-');\n}\n\nexport function clone(date) {\n\treturn new Date(date.getTime());\n}\n\nexport function timestampSec(date) {\n\treturn date.getTime()/NO_OF_MILLIS;\n}\n\nexport function timestampToMidnight(timestamp, roundAhead = false) {\n\tlet midnightTs = Math.floor(timestamp - (timestamp % SEC_IN_DAY));\n\tif(roundAhead) {\n\t\treturn midnightTs + SEC_IN_DAY;\n\t}\n\treturn midnightTs;\n}\n\n// export function getMonthsBetween(startDate, endDate) {}\n\nexport function getWeeksBetween(startDate, endDate) {\n\tlet weekStartDate = setDayToSunday(startDate);\n\treturn Math.ceil(getDaysBetween(weekStartDate, endDate) / NO_OF_DAYS_IN_WEEK);\n}\n\nexport function getDaysBetween(startDate, endDate) {\n\tlet millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS;\n\treturn (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay;\n}\n\nexport function areInSameMonth(startDate, endDate) {\n\treturn startDate.getMonth() === endDate.getMonth()\n\t\t&& startDate.getFullYear() === endDate.getFullYear();\n}\n\nexport function getMonthName(i, short=false) {\n\tlet monthName = MONTH_NAMES[i];\n\treturn short ? monthName.slice(0, 3) : monthName;\n}\n\nexport function getLastDateInMonth (month, year) {\n\treturn new Date(year, month + 1, 0); // 0: last day in previous month\n}\n\n// mutates\nexport function setDayToSunday(date) {\n\tlet newDate = clone(date);\n\tconst day = newDate.getDay();\n\tif(day !== 0) {\n\t\taddDays(newDate, (-1) * day);\n\t}\n\treturn newDate;\n}\n\n// mutates\nexport function addDays(date, numberOfDays) {\n\tdate.setDate(date.getDate() + numberOfDays);\n}\n", "import { makeSVGGroup } from '../utils/draw';\nimport { makeText, makePath, xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, percentageBar, getPaths, heatSquare } from '../utils/draw';\nimport { equilizeNoOfElements } from '../utils/draw-utils';\nimport { translateHoriLine, translateVertLine, animateRegion, animateBar,\n\tanimateDot, animatePath, animatePathStr } from '../utils/animate';\nimport { getMonthName } from '../utils/date-utils';\n\nclass ChartComponent {\n\tconstructor({\n\t\tlayerClass = '',\n\t\tlayerTransform = '',\n\t\tconstants,\n\n\t\tgetData,\n\t\tmakeElements,\n\t\tanimateElements\n\t}) {\n\t\tthis.layerTransform = layerTransform;\n\t\tthis.constants = constants;\n\n\t\tthis.makeElements = makeElements;\n\t\tthis.getData = getData;\n\n\t\tthis.animateElements = animateElements;\n\n\t\tthis.store = [];\n\t\tthis.labels = [];\n\n\t\tthis.layerClass = layerClass;\n\t\tthis.layerClass = typeof(this.layerClass) === 'function'\n\t\t\t? this.layerClass() : this.layerClass;\n\n\t\tthis.refresh();\n\t}\n\n\trefresh(data) {\n\t\tthis.data = data || this.getData();\n\t}\n\n\tsetup(parent) {\n\t\tthis.layer = makeSVGGroup(this.layerClass, this.layerTransform, parent);\n\t}\n\n\tmake() {\n\t\tthis.render(this.data);\n\t\tthis.oldData = this.data;\n\t}\n\n\trender(data) {\n\t\tthis.store = this.makeElements(data);\n\n\t\tthis.layer.textContent = '';\n\t\tthis.store.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t\tthis.labels.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t}\n\n\tupdate(animate = true) {\n\t\tthis.refresh();\n\t\tlet animateElements = [];\n\t\tif(animate) {\n\t\t\tanimateElements = this.animateElements(this.data) || [];\n\t\t}\n\t\treturn animateElements;\n\t}\n}\n\nlet componentConfigs = {\n\tdonutSlices: {\n\t\tlayerClass: 'donut-slices',\n\t\tmakeElements(data) {\n\t\t\treturn data.sliceStrings.map((s, i) => {\n\t\t\t\tlet slice = makePath(s, 'donut-path', data.colors[i], 'none', data.strokeWidth);\n\t\t\t\tslice.style.transition = 'transform .3s;';\n\t\t\t\treturn slice;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\treturn this.store.map((slice, i) => animatePathStr(slice, newData.sliceStrings[i]));\n\t\t},\n\t},\n\tpieSlices: {\n\t\tlayerClass: 'pie-slices',\n\t\tmakeElements(data) {\n\t\t\treturn data.sliceStrings.map((s, i) =>{\n\t\t\t\tlet slice = makePath(s, 'pie-path', 'none', data.colors[i]);\n\t\t\t\tslice.style.transition = 'transform .3s;';\n\t\t\t\treturn slice;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\treturn this.store.map((slice, i) =>\n\t\t\t\tanimatePathStr(slice, newData.sliceStrings[i])\n\t\t\t);\n\t\t}\n\t},\n\tpercentageBars: {\n\t\tlayerClass: 'percentage-bars',\n\t\tmakeElements(data) {\n\t\t\treturn data.xPositions.map((x, i) =>{\n\t\t\t\tlet y = 0;\n\t\t\t\tlet bar = percentageBar(x, y, data.widths[i],\n\t\t\t\t\tthis.constants.barHeight, this.constants.barDepth, data.colors[i]);\n\t\t\t\treturn bar;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\tyAxis: {\n\t\tlayerClass: 'y axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\tyLine(position, data.labels[i], this.constants.width,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos, shortenNumbers: this.constants.shortenNumbers})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.labels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tlabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\txAxis: {\n\t\tlayerClass: 'x axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\txLine(position, data.calcLabels[i], this.constants.height,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.calcLabels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.calcLabels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tcalcLabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateVertLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyMarkers: {\n\t\tlayerClass: 'y-markers',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(m =>\n\t\t\t\tyMarker(m.position, m.label, this.constants.width,\n\t\t\t\t\t{labelPos: m.options.labelPos, mode: 'span', lineType: 'dashed'})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.position);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.position);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tposition: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyRegions: {\n\t\tlayerClass: 'y-regions',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(r =>\n\t\t\t\tyRegion(r.startPos, r.endPos, this.constants.width,\n\t\t\t\t\tr.label, {labelPos: r.options.labelPos})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.endPos);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newStarts = newData.map(d => d.startPos);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.endPos);\n\t\t\tlet oldStarts = this.oldData.map(d => d.startPos);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tstartPos: oldStarts[i],\n\t\t\t\t\tendPos: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((rectGroup, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateRegion(\n\t\t\t\t\trectGroup, newStarts[i], newPos[i], oldPos[i]\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\theatDomain: {\n\t\tlayerClass: function() { return 'heat-domain domain-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet {index, colWidth, rowHeight, squareSize, radius, xTranslate} = this.constants;\n\t\t\tlet monthNameHeight = -12;\n\t\t\tlet x = xTranslate, y = 0;\n\n\t\t\tthis.serializedSubDomains = [];\n\n\t\t\tdata.cols.map((week, weekNo) => {\n\t\t\t\tif(weekNo === 1) {\n\t\t\t\t\tthis.labels.push(\n\t\t\t\t\t\tmakeText('domain-name', x, monthNameHeight, getMonthName(index, true).toUpperCase(),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfontSize: 9\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tweek.map((day, i) => {\n\t\t\t\t\tif(day.fill) {\n\t\t\t\t\t\tlet data = {\n\t\t\t\t\t\t\t'data-date': day.yyyyMmDd,\n\t\t\t\t\t\t\t'data-value': day.dataValue,\n\t\t\t\t\t\t\t'data-day': i\n\t\t\t\t\t\t};\n\t\t\t\t\t\tlet square = heatSquare('day', x, y, squareSize, radius, day.fill, data);\n\t\t\t\t\t\tthis.serializedSubDomains.push(square);\n\t\t\t\t\t}\n\t\t\t\t\ty += rowHeight;\n\t\t\t\t});\n\t\t\t\ty = 0;\n\t\t\t\tx += colWidth;\n\t\t\t});\n\n\t\t\treturn this.serializedSubDomains;\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\n\tbarGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'bar';\n\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\treturn datasetBar(\n\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\ty,\n\t\t\t\t\tdata.barWidth,\n\t\t\t\t\tc.color,\n\t\t\t\t\tdata.labels[j],\n\t\t\t\t\tj,\n\t\t\t\t\tdata.offsets[j],\n\t\t\t\t\t{\n\t\t\t\t\t\tzeroLine: data.zeroLine,\n\t\t\t\t\t\tbarsWidth: data.barsWidth,\n\t\t\t\t\t\tminHeight: c.minHeight\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn this.units;\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newOffsets = newData.offsets;\n\t\t\tlet newLabels = newData.labels;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldOffsets = this.oldData.offsets;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldOffsets, newOffsets] = equilizeNoOfElements(oldOffsets, newOffsets);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\toffsets: oldOffsets,\n\t\t\t\tlabels: newLabels,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tbarsWidth: this.oldData.barsWidth,\n\t\t\t\tbarWidth: this.oldData.barWidth,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((bar, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateBar(\n\t\t\t\t\tbar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i],\n\t\t\t\t\t{zeroLine: newData.zeroLine}\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\tlineGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'dot';\n\t\t\tthis.paths = {};\n\t\t\tif(!c.hideLine) {\n\t\t\t\tthis.paths = getPaths(\n\t\t\t\t\tdata.xPositions,\n\t\t\t\t\tdata.yPositions,\n\t\t\t\t\tc.color,\n\t\t\t\t\t{\n\t\t\t\t\t\theatline: c.heatline,\n\t\t\t\t\t\tregionFill: c.regionFill,\n\t\t\t\t\t\tspline: c.spline\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsvgDefs: c.svgDefs,\n\t\t\t\t\t\tzeroLine: data.zeroLine\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.units = [];\n\t\t\tif(!c.hideDots) {\n\t\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\t\treturn datasetDot(\n\t\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\t\ty,\n\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\tc.color,\n\t\t\t\t\t\t(c.valuesOverPoints ? data.values[j] : ''),\n\t\t\t\t\t\tj\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn Object.values(this.paths).concat(this.units);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newValues = newData.values;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldValues = this.oldData.values;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldValues, newValues] = equilizeNoOfElements(oldValues, newValues);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\tvalues: newValues,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tradius: this.oldData.radius,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tif(Object.keys(this.paths).length) {\n\t\t\t\tanimateElements = animateElements.concat(animatePath(\n\t\t\t\t\tthis.paths, newXPos, newYPos, newData.zeroLine, this.constants.spline));\n\t\t\t}\n\n\t\t\tif(this.units.length) {\n\t\t\t\tthis.units.map((dot, i) => {\n\t\t\t\t\tanimateElements = animateElements.concat(animateDot(\n\t\t\t\t\t\tdot, newXPos[i], newYPos[i]));\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn animateElements;\n\t\t}\n\t}\n};\n\nexport function getComponent(name, constants, getData) {\n\tlet keys = Object.keys(componentConfigs).filter(k => name.includes(k));\n\tlet config = componentConfigs[keys[0]];\n\tObject.assign(config, {\n\t\tconstants: constants,\n\t\tgetData: getData\n\t});\n\treturn new ChartComponent(config);\n}\n", "import { floatTwo } from './helpers';\n\nfunction normalize(x) {\n\t// Calculates mantissa and exponent of a number\n\t// Returns normalized number and exponent\n\t// https://stackoverflow.com/q/9383593/6495043\n\n\tif(x===0) {\n\t\treturn [0, 0];\n\t}\n\tif(isNaN(x)) {\n\t\treturn {mantissa: -6755399441055744, exponent: 972};\n\t}\n\tvar sig = x > 0 ? 1 : -1;\n\tif(!isFinite(x)) {\n\t\treturn {mantissa: sig * 4503599627370496, exponent: 972};\n\t}\n\n\tx = Math.abs(x);\n\tvar exp = Math.floor(Math.log10(x));\n\tvar man = x/Math.pow(10, exp);\n\n\treturn [sig * man, exp];\n}\n\nfunction getChartRangeIntervals(max, min=0) {\n\tlet upperBound = Math.ceil(max);\n\tlet lowerBound = Math.floor(min);\n\tlet range = upperBound - lowerBound;\n\n\tlet noOfParts = range;\n\tlet partSize = 1;\n\n\t// To avoid too many partitions\n\tif(range > 5) {\n\t\tif(range % 2 !== 0) {\n\t\t\tupperBound++;\n\t\t\t// Recalc range\n\t\t\trange = upperBound - lowerBound;\n\t\t}\n\t\tnoOfParts = range/2;\n\t\tpartSize = 2;\n\t}\n\n\t// Special case: 1 and 2\n\tif(range <= 2) {\n\t\tnoOfParts = 4;\n\t\tpartSize = range/noOfParts;\n\t}\n\n\t// Special case: 0\n\tif(range === 0) {\n\t\tnoOfParts = 5;\n\t\tpartSize = 1;\n\t}\n\n\tlet intervals = [];\n\tfor(var i = 0; i <= noOfParts; i++){\n\t\tintervals.push(lowerBound + partSize * i);\n\t}\n\treturn intervals;\n}\n\nfunction getChartIntervals(maxValue, minValue=0) {\n\tlet [normalMaxValue, exponent] = normalize(maxValue);\n\tlet normalMinValue = minValue ? minValue/Math.pow(10, exponent): 0;\n\n\t// Allow only 7 significant digits\n\tnormalMaxValue = normalMaxValue.toFixed(6);\n\n\tlet intervals = getChartRangeIntervals(normalMaxValue, normalMinValue);\n\tintervals = intervals.map(value => value * Math.pow(10, exponent));\n\treturn intervals;\n}\n\nexport function calcChartIntervals(values, withMinimum=false) {\n\t//*** Where the magic happens ***\n\n\t// Calculates best-fit y intervals from given values\n\t// and returns the interval array\n\n\tlet maxValue = Math.max(...values);\n\tlet minValue = Math.min(...values);\n\n\t// Exponent to be used for pretty print\n\tlet exponent = 0, intervals = []; // eslint-disable-line no-unused-vars\n\n\tfunction getPositiveFirstIntervals(maxValue, absMinValue) {\n\t\tlet intervals = getChartIntervals(maxValue);\n\n\t\tlet intervalSize = intervals[1] - intervals[0];\n\n\t\t// Then unshift the negative values\n\t\tlet value = 0;\n\t\tfor(var i = 1; value < absMinValue; i++) {\n\t\t\tvalue += intervalSize;\n\t\t\tintervals.unshift((-1) * value);\n\t\t}\n\t\treturn intervals;\n\t}\n\n\t// CASE I: Both non-negative\n\n\tif(maxValue >= 0 && minValue >= 0) {\n\t\texponent = normalize(maxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(maxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(maxValue, minValue);\n\t\t}\n\t}\n\n\t// CASE II: Only minValue negative\n\n\telse if(maxValue > 0 && minValue < 0) {\n\t\t// `withMinimum` irrelevant in this case,\n\t\t// We'll be handling both sides of zero separately\n\t\t// (both starting from zero)\n\t\t// Because ceil() and floor() behave differently\n\t\t// in those two regions\n\n\t\tlet absMinValue = Math.abs(minValue);\n\n\t\tif(maxValue >= absMinValue) {\n\t\t\texponent = normalize(maxValue)[1];\n\t\t\tintervals = getPositiveFirstIntervals(maxValue, absMinValue);\n\t\t} else {\n\t\t\t// Mirror: maxValue => absMinValue, then change sign\n\t\t\texponent = normalize(absMinValue)[1];\n\t\t\tlet posIntervals = getPositiveFirstIntervals(absMinValue, maxValue);\n\t\t\tintervals = posIntervals.reverse().map(d => d * (-1));\n\t\t}\n\n\t}\n\n\t// CASE III: Both non-positive\n\n\telse if(maxValue <= 0 && minValue <= 0) {\n\t\t// Mirrored Case I:\n\t\t// Work with positives, then reverse the sign and array\n\n\t\tlet pseudoMaxValue = Math.abs(minValue);\n\t\tlet pseudoMinValue = Math.abs(maxValue);\n\n\t\texponent = normalize(pseudoMaxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue, pseudoMinValue);\n\t\t}\n\n\t\tintervals = intervals.reverse().map(d => d * (-1));\n\t}\n\n\treturn intervals;\n}\n\nexport function getZeroIndex(yPts) {\n\tlet zeroIndex;\n\tlet interval = getIntervalSize(yPts);\n\tif(yPts.indexOf(0) >= 0) {\n\t\t// the range has a given zero\n\t\t// zero-line on the chart\n\t\tzeroIndex = yPts.indexOf(0);\n\t} else if(yPts[0] > 0) {\n\t\t// Minimum value is positive\n\t\t// zero-line is off the chart: below\n\t\tlet min = yPts[0];\n\t\tzeroIndex = (-1) * min / interval;\n\t} else {\n\t\t// Maximum value is negative\n\t\t// zero-line is off the chart: above\n\t\tlet max = yPts[yPts.length - 1];\n\t\tzeroIndex = (-1) * max / interval + (yPts.length - 1);\n\t}\n\treturn zeroIndex;\n}\n\nexport function getRealIntervals(max, noOfIntervals, min = 0, asc = 1) {\n\tlet range = max - min;\n\tlet part = range * 1.0 / noOfIntervals;\n\tlet intervals = [];\n\n\tfor(var i = 0; i <= noOfIntervals; i++) {\n\t\tintervals.push(min + part * i);\n\t}\n\n\treturn asc ? intervals : intervals.reverse();\n}\n\nexport function getIntervalSize(orderedArray) {\n\treturn orderedArray[1] - orderedArray[0];\n}\n\nexport function getValueRange(orderedArray) {\n\treturn orderedArray[orderedArray.length-1] - orderedArray[0];\n}\n\nexport function scale(val, yAxis) {\n\treturn floatTwo(yAxis.zeroLine - val * yAxis.scaleMultiplier);\n}\n\nexport function isInRange(val, min, max) {\n\treturn val > min && val < max;\n}\n\nexport function isInRange2D(coord, minCoord, maxCoord) {\n\treturn isInRange(coord[0], minCoord[0], maxCoord[0])\n\t\t&& isInRange(coord[1], minCoord[1], maxCoord[1]);\n}\n\nexport function getClosestInArray(goal, arr, index = false) {\n\tlet closest = arr.reduce(function(prev, curr) {\n\t\treturn (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);\n\t}, []);\n\n\treturn index ? arr.indexOf(closest) : closest;\n}\n\nexport function calcDistribution(values, distributionSize) {\n\t// Assume non-negative values,\n\t// implying distribution minimum at zero\n\n\tlet dataMaxValue = Math.max(...values);\n\n\tlet distributionStep = 1 / (distributionSize - 1);\n\tlet distribution = [];\n\n\tfor(var i = 0; i < distributionSize; i++) {\n\t\tlet checkpoint = dataMaxValue * (distributionStep * i);\n\t\tdistribution.push(checkpoint);\n\t}\n\n\treturn distribution;\n}\n\nexport function getMaxCheckpoint(value, distribution) {\n\treturn distribution.filter(d => d < value).length;\n}\n", "import { fillArray } from '../utils/helpers';\nimport { DEFAULT_AXIS_CHART_TYPE, AXIS_DATASET_CHART_TYPES, DEFAULT_CHAR_WIDTH } from '../utils/constants';\n\nexport function dataPrep(data, type) {\n\tdata.labels = data.labels || [];\n\n\tlet datasetLength = data.labels.length;\n\n\t// Datasets\n\tlet datasets = data.datasets;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\tif(!datasets) {\n\t\t// default\n\t\tdatasets = [{\n\t\t\tvalues: zeroArray\n\t\t}];\n\t}\n\n\tdatasets.map(d=> {\n\t\t// Set values\n\t\tif(!d.values) {\n\t\t\td.values = zeroArray;\n\t\t} else {\n\t\t\t// Check for non values\n\t\t\tlet vals = d.values;\n\t\t\tvals = vals.map(val => (!isNaN(val) ? val : 0));\n\n\t\t\t// Trim or extend\n\t\t\tif(vals.length > datasetLength) {\n\t\t\t\tvals = vals.slice(0, datasetLength);\n\t\t\t} else {\n\t\t\t\tvals = fillArray(vals, datasetLength - vals.length, 0);\n\t\t\t}\n\t\t\td.values = vals;\n\t\t}\n\n\t\t// Set type\n\t\tif(!d.chartType ) {\n\t\t\tif(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;\n\t\t\td.chartType = type;\n\t\t}\n\n\t});\n\n\t// Markers\n\n\t// Regions\n\t// data.yRegions = data.yRegions || [];\n\tif(data.yRegions) {\n\t\tdata.yRegions.map(d => {\n\t\t\tif(d.end < d.start) {\n\t\t\t\t[d.start, d.end] = [d.end, d.start];\n\t\t\t}\n\t\t});\n\t}\n\n\treturn data;\n}\n\nexport function zeroDataPrep(realData) {\n\tlet datasetLength = realData.labels.length;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\n\tlet zeroData = {\n\t\tlabels: realData.labels.slice(0, -1),\n\t\tdatasets: realData.datasets.map(d => {\n\t\t\treturn {\n\t\t\t\tname: '',\n\t\t\t\tvalues: zeroArray.slice(0, -1),\n\t\t\t\tchartType: d.chartType\n\t\t\t};\n\t\t}),\n\t};\n\n\tif(realData.yMarkers) {\n\t\tzeroData.yMarkers = [\n\t\t\t{\n\t\t\t\tvalue: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\tif(realData.yRegions) {\n\t\tzeroData.yRegions = [\n\t\t\t{\n\t\t\t\tstart: 0,\n\t\t\t\tend: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\treturn zeroData;\n}\n\nexport function getShortenedLabels(chartWidth, labels=[], isSeries=true) {\n\tlet allowedSpace = chartWidth / labels.length;\n\tif(allowedSpace <= 0) allowedSpace = 1;\n\tlet allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;\n\n\tlet seriesMultiple;\n\tif(isSeries) {\n\t\t// Find the maximum label length for spacing calculations\n\t\tlet maxLabelLength = Math.max(...labels.map(label => label.length));\n\t\tseriesMultiple = Math.ceil(maxLabelLength/allowedLetters);\n\t}\n\n\tlet calcLabels = labels.map((label, i) => {\n\t\tlabel += \"\";\n\t\tif(label.length > allowedLetters) {\n\n\t\t\tif(!isSeries) {\n\t\t\t\tif(allowedLetters-3 > 0) {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters-3) + \" ...\";\n\t\t\t\t} else {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters) + '..';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(i % seriesMultiple !== 0) {\n\t\t\t\t\tlabel = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn label;\n\t});\n\n\treturn calcLabels;\n}\n", "import '../css/charts.scss';\n\n// import MultiAxisChart from './charts/MultiAxisChart';\nimport PercentageChart from './charts/PercentageChart';\nimport PieChart from './charts/PieChart';\nimport Heatmap from './charts/Heatmap';\nimport AxisChart from './charts/AxisChart';\nimport DonutChart from './charts/DonutChart';\n\nconst chartTypes = {\n\tbar: AxisChart,\n\tline: AxisChart,\n\t// multiaxis: MultiAxisChart,\n\tpercentage: PercentageChart,\n\theatmap: Heatmap,\n\tpie: PieChart,\n\tdonut: DonutChart,\n};\n\nfunction getChartByType(chartType = 'line', parent, options) {\n\tif (chartType === 'axis-mixed') {\n\t\toptions.type = 'line';\n\t\treturn new AxisChart(parent, options);\n\t}\n\n\tif (!chartTypes[chartType]) {\n\t\tconsole.error(\"Undefined chart type: \" + chartType);\n\t\treturn;\n\t}\n\n\treturn new chartTypes[chartType](parent, options);\n}\n\nclass Chart {\n\tconstructor(parent, options) {\n\t\treturn getChartByType(options.type, parent, options);\n\t}\n}\n\nexport { Chart, PercentageChart, PieChart, Heatmap, AxisChart };", "import { $ } from '../utils/dom';\nimport { TOOLTIP_POINTER_TRIANGLE_HEIGHT } from '../utils/constants';\n\nexport default class SvgTip {\n\tconstructor({\n\t\tparent = null,\n\t\tcolors = []\n\t}) {\n\t\tthis.parent = parent;\n\t\tthis.colors = colors;\n\t\tthis.titleName = '';\n\t\tthis.titleValue = '';\n\t\tthis.listValues = [];\n\t\tthis.titleValueFirst = 0;\n\n\t\tthis.x = 0;\n\t\tthis.y = 0;\n\n\t\tthis.top = 0;\n\t\tthis.left = 0;\n\n\t\tthis.setup();\n\t}\n\n\tsetup() {\n\t\tthis.makeTooltip();\n\t}\n\n\trefresh() {\n\t\tthis.fill();\n\t\tthis.calcPosition();\n\t}\n\n\tmakeTooltip() {\n\t\tthis.container = $.create('div', {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'graph-svg-tip comparison',\n\t\t\tinnerHTML: `\n\t\t\t\t\n\t\t\t\t
`\n\t\t});\n\t\tthis.hideTip();\n\n\t\tthis.title = this.container.querySelector('.title');\n\t\tthis.dataPointList = this.container.querySelector('.data-point-list');\n\n\t\tthis.parent.addEventListener('mouseleave', () => {\n\t\t\tthis.hideTip();\n\t\t});\n\t}\n\n\tfill() {\n\t\tlet title;\n\t\tif(this.index) {\n\t\t\tthis.container.setAttribute('data-point-index', this.index);\n\t\t}\n\t\tif(this.titleValueFirst) {\n\t\t\ttitle = `${this.titleValue}${this.titleName}`;\n\t\t} else {\n\t\t\ttitle = `${this.titleName}${this.titleValue}`;\n\t\t}\n\t\tthis.title.innerHTML = title;\n\t\tthis.dataPointList.innerHTML = '';\n\n\t\tthis.listValues.map((set, i) => {\n\t\t\tconst color = this.colors[i] || 'black';\n\t\t\tlet value = set.formatted === 0 || set.formatted ? set.formatted : set.value;\n\n\t\t\tlet li = $.create('li', {\n\t\t\t\tstyles: {\n\t\t\t\t\t'border-top': `3px solid ${color}`\n\t\t\t\t},\n\t\t\t\tinnerHTML: `${ value === 0 || value ? value : '' }\n\t\t\t\t\t${set.title ? set.title : '' }`\n\t\t\t});\n\n\t\t\tthis.dataPointList.appendChild(li);\n\t\t});\n\t}\n\n\tcalcPosition() {\n\t\tlet width = this.container.offsetWidth;\n\n\t\tthis.top = this.y - this.container.offsetHeight\n\t\t\t- TOOLTIP_POINTER_TRIANGLE_HEIGHT;\n\t\tthis.left = this.x - width/2;\n\t\tlet maxLeft = this.parent.offsetWidth - width;\n\n\t\tlet pointer = this.container.querySelector('.svg-pointer');\n\n\t\tif(this.left < 0) {\n\t\t\tpointer.style.left = `calc(50% - ${-1 * this.left}px)`;\n\t\t\tthis.left = 0;\n\t\t} else if(this.left > maxLeft) {\n\t\t\tlet delta = this.left - maxLeft;\n\t\t\tlet pointerOffset = `calc(50% + ${delta}px)`;\n\t\t\tpointer.style.left = pointerOffset;\n\n\t\t\tthis.left = maxLeft;\n\t\t} else {\n\t\t\tpointer.style.left = `50%`;\n\t\t}\n\t}\n\n\tsetValues(x, y, title = {}, listValues = [], index = -1) {\n\t\tthis.titleName = title.name;\n\t\tthis.titleValue = title.value;\n\t\tthis.listValues = listValues;\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.titleValueFirst = title.valueFirst || 0;\n\t\tthis.index = index;\n\t\tthis.refresh();\n\t}\n\n\thideTip() {\n\t\tthis.container.style.top = '0px';\n\t\tthis.container.style.left = '0px';\n\t\tthis.container.style.opacity = '0';\n\t}\n\n\tshowTip() {\n\t\tthis.container.style.top = this.top + 'px';\n\t\tthis.container.style.left = this.left + 'px';\n\t\tthis.container.style.opacity = '1';\n\t}\n}\n", "export const CSSTEXT = \".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}\";", "import SvgTip from '../objects/SvgTip';\nimport { $, isElementInViewport, getElementContentWidth, isHidden } from '../utils/dom';\nimport { makeSVGContainer, makeSVGDefs, makeSVGGroup, makeText } from '../utils/draw';\nimport { BASE_MEASURES, getExtraHeight, getExtraWidth, getTopOffset, getLeftOffset,\n\tINIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS} from '../utils/constants';\nimport { getColor, isValidColor } from '../utils/colors';\nimport { runSMILAnimation } from '../utils/animation';\nimport { downloadFile, prepareForExport } from '../utils/export';\nimport { deepClone } from '../utils/helpers';\n\nexport default class BaseChart {\n\tconstructor(parent, options) {\n\t\t// deepclone options to avoid making changes to orignal object\n\t\toptions = deepClone(options);\n\n\t\tthis.parent = typeof parent === 'string'\n\t\t\t? document.querySelector(parent)\n\t\t\t: parent;\n\n\t\tif (!(this.parent instanceof HTMLElement)) {\n\t\t\tthrow new Error('No `parent` element to render on was provided.');\n\t\t}\n\n\t\tthis.rawChartArgs = options;\n\n\t\tthis.title = options.title || '';\n\t\tthis.type = options.type || '';\n\n\t\tthis.realData = this.prepareData(options.data);\n\t\tthis.data = this.prepareFirstData(this.realData);\n\n\t\tthis.colors = this.validateColors(options.colors, this.type);\n\n\t\tthis.config = {\n\t\t\tshowTooltip: 1, // calculate\n\t\t\tshowLegend: 1, // calculate\n\t\t\tisNavigable: options.isNavigable || 0,\n\t\t\tanimate: (typeof options.animate !== 'undefined') ? options.animate : 1,\n\t\t\ttruncateLegends: options.truncateLegends || 1\n\t\t};\n\n\t\tthis.measures = JSON.parse(JSON.stringify(BASE_MEASURES));\n\t\tlet m = this.measures;\n\t\tthis.setMeasures(options);\n\t\tif(!this.title.length) { m.titleHeight = 0; }\n\t\tif(!this.config.showLegend) m.legendHeight = 0;\n\t\tthis.argHeight = options.height || m.baseHeight;\n\n\t\tthis.state = {};\n\t\tthis.options = {};\n\n\t\tthis.initTimeout = INIT_CHART_UPDATE_TIMEOUT;\n\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.overlays = [];\n\t\t}\n\n\t\tthis.configure(options);\n\t}\n\n\tprepareData(data) {\n\t\treturn data;\n\t}\n\n\tprepareFirstData(data) {\n\t\treturn data;\n\t}\n\n\tvalidateColors(colors, type) {\n\t\tconst validColors = [];\n\t\tcolors = (colors || []).concat(DEFAULT_COLORS[type]);\n\t\tcolors.forEach((string) => {\n\t\t\tconst color = getColor(string);\n\t\t\tif(!isValidColor(color)) {\n\t\t\t\tconsole.warn('\"' + string + '\" is not a valid color.');\n\t\t\t} else {\n\t\t\t\tvalidColors.push(color);\n\t\t\t}\n\t\t});\n\t\treturn validColors;\n\t}\n\n\tsetMeasures() {\n\t\t// Override measures, including those for title and legend\n\t\t// set config for legend and title\n\t}\n\n\tconfigure() {\n\t\tlet height = this.argHeight;\n\t\tthis.baseHeight = height;\n\t\tthis.height = height - getExtraHeight(this.measures);\n\n\t\t// Bind window events\n\t\tthis.boundDrawFn = () => this.draw(true);\n\t\tif (ResizeObserver) {\n\t\t\tthis.resizeObserver = new ResizeObserver(this.boundDrawFn);\n\t\t\tthis.resizeObserver.observe(this.parent);\n\t\t}\n\t\twindow.addEventListener('resize', this.boundDrawFn);\n\t\twindow.addEventListener('orientationchange', this.boundDrawFn);\n\t}\n\n\tdestroy() {\n\t\tif (this.resizeObserver) this.resizeObserver.disconnect();\n\t\twindow.removeEventListener('resize', this.boundDrawFn);\n\t\twindow.removeEventListener('orientationchange', this.boundDrawFn);\n\t}\n\n\t// Has to be called manually\n\tsetup() {\n\t\tthis.makeContainer();\n\t\tthis.updateWidth();\n\t\tthis.makeTooltip();\n\n\t\tthis.draw(false, true);\n\t}\n\n\tmakeContainer() {\n\t\t// Chart needs a dedicated parent element\n\t\tthis.parent.innerHTML = '';\n\n\t\tlet args = {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'chart-container'\n\t\t};\n\n\t\tif(this.independentWidth) {\n\t\t\targs.styles = { width: this.independentWidth + 'px' };\n\t\t}\n\n\t\tthis.container = $.create('div', args);\n\t}\n\n\tmakeTooltip() {\n\t\tthis.tip = new SvgTip({\n\t\t\tparent: this.container,\n\t\t\tcolors: this.colors\n\t\t});\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {}\n\n\tdraw(onlyWidthChange=false, init=false) {\n\t\tif (onlyWidthChange && isHidden(this.parent)) {\n\t\t\t// Don't update anything if the chart is hidden\n\t\t\treturn;\n\t\t}\n\t\tthis.updateWidth();\n\n\t\tthis.calc(onlyWidthChange);\n\t\tthis.makeChartArea();\n\t\tthis.setupComponents();\n\n\t\tthis.components.forEach(c => c.setup(this.drawArea));\n\t\t// this.components.forEach(c => c.make());\n\t\tthis.render(this.components, false);\n\n\t\tif(init) {\n\t\t\tthis.data = this.realData;\n\t\t\tsetTimeout(() => {this.update(this.data);}, this.initTimeout);\n\t\t}\n\n\t\tthis.renderLegend();\n\n\t\tthis.setupNavigation(init);\n\t}\n\n\tcalc() {} // builds state\n\n\tupdateWidth() {\n\t\tthis.baseWidth = getElementContentWidth(this.parent);\n\t\tthis.width = this.baseWidth - getExtraWidth(this.measures);\n\t}\n\n\tmakeChartArea() {\n\t\tif(this.svg) {\n\t\t\tthis.container.removeChild(this.svg);\n\t\t}\n\t\tlet m = this.measures;\n\n\t\tthis.svg = makeSVGContainer(\n\t\t\tthis.container,\n\t\t\t'frappe-chart chart',\n\t\t\tthis.baseWidth,\n\t\t\tthis.baseHeight\n\t\t);\n\t\tthis.svgDefs = makeSVGDefs(this.svg);\n\n\t\tif(this.title.length) {\n\t\t\tthis.titleEL = makeText(\n\t\t\t\t'title',\n\t\t\t\tm.margins.left,\n\t\t\t\tm.margins.top,\n\t\t\t\tthis.title,\n\t\t\t\t{\n\t\t\t\t\tfontSize: m.titleFontSize,\n\t\t\t\t\tfill: '#666666',\n\t\t\t\t\tdy: m.titleFontSize\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tlet top = getTopOffset(m);\n\t\tthis.drawArea = makeSVGGroup(\n\t\t\tthis.type + '-chart chart-draw-area',\n\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t);\n\n\t\tif(this.config.showLegend) {\n\t\t\ttop += this.height + m.paddings.bottom;\n\t\t\tthis.legendArea = makeSVGGroup(\n\t\t\t\t'chart-legend',\n\t\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t\t);\n\t\t}\n\n\t\tif(this.title.length) { this.svg.appendChild(this.titleEL); }\n\t\tthis.svg.appendChild(this.drawArea);\n\t\tif(this.config.showLegend) { this.svg.appendChild(this.legendArea); }\n\n\t\tthis.updateTipOffset(getLeftOffset(m), getTopOffset(m));\n\t}\n\n\tupdateTipOffset(x, y) {\n\t\tthis.tip.offset = {\n\t\t\tx: x,\n\t\t\ty: y\n\t\t};\n\t}\n\n\tsetupComponents() { this.components = new Map(); }\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\t\tthis.data = this.prepareData(data);\n\t\tthis.calc(); // builds state\n\t\tthis.render(this.components, this.config.animate);\n\t\tthis.renderLegend();\n\t}\n\n\trender(components=this.components, animate=true) {\n\t\tif(this.config.isNavigable) {\n\t\t\t// Remove all existing overlays\n\t\t\tthis.overlays.map(o => o.parentNode.removeChild(o));\n\t\t\t// ref.parentNode.insertBefore(element, ref);\n\t\t}\n\t\tlet elementsToAnimate = [];\n\t\t// Can decouple to this.refreshComponents() first to save animation timeout\n\t\tcomponents.forEach(c => {\n\t\t\telementsToAnimate = elementsToAnimate.concat(c.update(animate));\n\t\t});\n\t\tif(elementsToAnimate.length > 0) {\n\t\t\trunSMILAnimation(this.container, this.svg, elementsToAnimate);\n\t\t\tsetTimeout(() => {\n\t\t\t\tcomponents.forEach(c => c.make());\n\t\t\t\tthis.updateNav();\n\t\t\t}, CHART_POST_ANIMATE_TIMEOUT);\n\t\t} else {\n\t\t\tcomponents.forEach(c => c.make());\n\t\t\tthis.updateNav();\n\t\t}\n\t}\n\n\tupdateNav() {\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.makeOverlay();\n\t\t\tthis.bindUnits();\n\t\t}\n\t}\n\n\trenderLegend() {}\n\n\tsetupNavigation(init=false) {\n\t\tif(!this.config.isNavigable) return;\n\n\t\tif(init) {\n\t\t\tthis.bindOverlay();\n\n\t\t\tthis.keyActions = {\n\t\t\t\t'13': this.onEnterKey.bind(this),\n\t\t\t\t'37': this.onLeftArrow.bind(this),\n\t\t\t\t'38': this.onUpArrow.bind(this),\n\t\t\t\t'39': this.onRightArrow.bind(this),\n\t\t\t\t'40': this.onDownArrow.bind(this),\n\t\t\t};\n\n\t\t\tdocument.addEventListener('keydown', (e) => {\n\t\t\t\tif(isElementInViewport(this.container)) {\n\t\t\t\t\te = e || window.event;\n\t\t\t\t\tif(this.keyActions[e.keyCode]) {\n\t\t\t\t\t\tthis.keyActions[e.keyCode]();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tmakeOverlay() {}\n\tupdateOverlay() {}\n\tbindOverlay() {}\n\tbindUnits() {}\n\n\tonLeftArrow() {}\n\tonRightArrow() {}\n\tonUpArrow() {}\n\tonDownArrow() {}\n\tonEnterKey() {}\n\n\taddDataPoint() {}\n\tremoveDataPoint() {}\n\n\tgetDataPoint() {}\n\tsetCurrentDataPoint() {}\n\n\tupdateDataset() {}\n\n\texport() {\n\t\tlet chartSvg = prepareForExport(this.svg);\n\t\tdownloadFile(this.title || 'Chart', [chartSvg]);\n\t}\n}\n", "import BaseChart from './BaseChart';\nimport { truncateString } from '../utils/draw-utils';\nimport { legendDot } from '../utils/draw';\nimport { round } from '../utils/helpers';\nimport { getExtraWidth } from '../utils/constants';\n\nexport default class AggregationChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\n\t\tthis.config.formatTooltipY = (args.tooltipOptions || {}).formatTooltipY;\n\t\tthis.config.maxSlices = args.maxSlices || 20;\n\t\tthis.config.maxLegendPoints = args.maxLegendPoints || 20;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\t\tlet maxSlices = this.config.maxSlices;\n\t\ts.sliceTotals = [];\n\n\t\tlet allTotals = this.data.labels.map((label, i) => {\n\t\t\tlet total = 0;\n\t\t\tthis.data.datasets.map(e => {\n\t\t\t\ttotal += e.values[i];\n\t\t\t});\n\t\t\treturn [total, label];\n\t\t}).filter(d => { return d[0] >= 0; }); // keep only positive results\n\n\t\tlet totals = allTotals;\n\t\tif(allTotals.length > maxSlices) {\n\t\t\t// Prune and keep a grey area for rest as per maxSlices\n\t\t\tallTotals.sort((a, b) => { return b[0] - a[0]; });\n\n\t\t\ttotals = allTotals.slice(0, maxSlices-1);\n\t\t\tlet remaining = allTotals.slice(maxSlices-1);\n\n\t\t\tlet sumOfRemaining = 0;\n\t\t\tremaining.map(d => {sumOfRemaining += d[0];});\n\t\t\ttotals.push([sumOfRemaining, 'Rest']);\n\t\t\tthis.colors[maxSlices-1] = 'grey';\n\t\t}\n\n\t\ts.labels = [];\n\t\ttotals.map(d => {\n\t\t\ts.sliceTotals.push(round(d[0]));\n\t\t\ts.labels.push(d[1]);\n\t\t});\n\n\t\ts.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0);\n\n\t\tthis.center = {\n\t\t\tx: this.width / 2,\n\t\t\ty: this.height / 2\n\t\t};\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.state;\n\t\tthis.legendArea.textContent = '';\n\t\tthis.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);\n\n\t\tlet count = 0;\n\t\tlet y = 0;\n\t\tthis.legendTotals.map((d, i) => {\n\t\t\tlet barWidth = 150;\n\t\t\tlet divisor = Math.floor(\n\t\t\t\t(this.width - getExtraWidth(this.measures))/barWidth\n\t\t\t);\n\t\t\tif (this.legendTotals.length < divisor) {\n\t\t\t\tbarWidth = this.width/this.legendTotals.length;\n\t\t\t}\n\t\t\tif(count > divisor) {\n\t\t\t\tcount = 0;\n\t\t\t\ty += 20;\n\t\t\t}\n\t\t\tlet x = barWidth * count + 5;\n\t\t\tlet label = this.config.truncateLegends ? truncateString(s.labels[i], barWidth/10) : s.labels[i];\n\t\t\tlet formatted = this.config.formatTooltipY ? this.config.formatTooltipY(d) : d;\n\t\t\tlet dot = legendDot(\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\t5,\n\t\t\t\tthis.colors[i],\n\t\t\t\t`${label}: ${formatted}`,\n\t\t\t\tfalse\n\t\t\t);\n\t\t\tthis.legendArea.appendChild(dot);\n\t\t\tcount++;\n\t\t});\n\t}\n}\n", "import AggregationChart from './AggregationChart';\nimport { getOffset } from '../utils/dom';\nimport { getComponent } from '../objects/ChartComponents';\nimport { PERCENTAGE_BAR_DEFAULT_HEIGHT, PERCENTAGE_BAR_DEFAULT_DEPTH } from '../utils/constants';\n\nexport default class PercentageChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'percentage';\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.barOptions = options.barOptions || {};\n\n\t\tlet b = this.barOptions;\n\t\tb.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT;\n\t\tb.depth = b.depth || PERCENTAGE_BAR_DEFAULT_DEPTH;\n\n\t\tm.paddings.right = 30;\n\t\tm.legendHeight = 60;\n\t\tm.baseHeight = (b.height + b.depth * 0.5) * 8;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'percentageBars',\n\t\t\t\t{\n\t\t\t\t\tbarHeight: this.barOptions.height,\n\t\t\t\t\tbarDepth: this.barOptions.depth,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xPositions,\n\t\t\t\t\t\twidths: s.widths,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\n\t\ts.xPositions = [];\n\t\ts.widths = [];\n\n\t\tlet xPos = 0;\n\t\ts.sliceTotals.map((value) => {\n\t\t\tlet width = this.width * value / s.grandTotal;\n\t\t\ts.widths.push(width);\n\t\t\ts.xPositions.push(xPos);\n\t\t\txPos += width;\n\t\t});\n\t}\n\n\tmakeDataByIndex() { }\n\n\tbindTooltip() {\n\t\tlet s = this.state;\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet bars = this.components.get('percentageBars').store;\n\t\t\tlet bar = e.target;\n\t\t\tif(bars.includes(bar)) {\n\n\t\t\t\tlet i = bars.indexOf(bar);\n\t\t\t\tlet gOff = getOffset(this.container), pOff = getOffset(bar);\n\n\t\t\t\tlet x = pOff.left - gOff.left + parseInt(bar.getAttribute('width'))/2;\n\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\tlet title = (this.formattedLabels && this.formattedLabels.length>0\n\t\t\t\t\t? this.formattedLabels[i] : this.state.labels[i]) + ': ';\n\t\t\t\tlet fraction = s.sliceTotals[i]/s.grandTotal;\n\n\t\t\t\tthis.tip.setValues(x, y, {name: title, value: (fraction*100).toFixed(1) + \"%\"});\n\t\t\t\tthis.tip.showTip();\n\t\t\t}\n\t\t});\n\t}\n}\n", "import AggregationChart from './AggregationChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset } from '../utils/dom';\nimport { getPositionByAngle } from '../utils/helpers';\nimport { makeArcPathStr, makeCircleStr } from '../utils/draw';\nimport { lightenDarkenColor } from '../utils/colors';\nimport { transform } from '../utils/animation';\nimport { FULL_ANGLE } from '../utils/constants';\n\nexport default class PieChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'pie';\n\t\tthis.initTimeout = 0;\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\t\tthis.mouseMove = this.mouseMove.bind(this);\n\t\tthis.mouseLeave = this.mouseLeave.bind(this);\n\n\t\tthis.hoverRadio = args.hoverRadio || 0.1;\n\t\tthis.config.startAngle = args.startAngle || 0;\n\n\t\tthis.clockWise = args.clockWise || false;\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\t\tthis.radius = (this.height > this.width ? this.center.x : this.center.y);\n\n\t\tconst { radius, clockWise } = this;\n\n\t\tconst prevSlicesProperties = s.slicesProperties || [];\n\t\ts.sliceStrings = [];\n\t\ts.slicesProperties = [];\n\t\tlet curAngle = 180 - this.config.startAngle;\n\t\ts.sliceTotals.map((total, i) => {\n\t\t\tconst startAngle = curAngle;\n\t\t\tconst originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;\n\t\t\tconst largeArc = originDiffAngle > 180 ? 1: 0;\n\t\t\tconst diffAngle = clockWise ? -originDiffAngle : originDiffAngle;\n\t\t\tconst endAngle = curAngle = curAngle + diffAngle;\n\t\t\tconst startPosition = getPositionByAngle(startAngle, radius);\n\t\t\tconst endPosition = getPositionByAngle(endAngle, radius);\n\n\t\t\tconst prevProperty = this.init && prevSlicesProperties[i];\n\n\t\t\tlet curStart,curEnd;\n\t\t\tif(this.init) {\n\t\t\t\tcurStart = prevProperty ? prevProperty.startPosition : startPosition;\n\t\t\t\tcurEnd = prevProperty ? prevProperty.endPosition : startPosition;\n\t\t\t} else {\n\t\t\t\tcurStart = startPosition;\n\t\t\t\tcurEnd = endPosition;\n\t\t\t}\n\t\t\tconst curPath =\n\t\t\t\toriginDiffAngle === 360\n\t\t\t\t\t? makeCircleStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc)\n\t\t\t\t\t: makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc);\n\n\t\t\ts.sliceStrings.push(curPath);\n\t\t\ts.slicesProperties.push({\n\t\t\t\tstartPosition,\n\t\t\t\tendPosition,\n\t\t\t\tvalue: total,\n\t\t\t\ttotal: s.grandTotal,\n\t\t\t\tstartAngle,\n\t\t\t\tendAngle,\n\t\t\t\tangle: diffAngle\n\t\t\t});\n\n\t\t});\n\t\tthis.init = 0;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'pieSlices',\n\t\t\t\t{ },\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsliceStrings: s.sliceStrings,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalTranslateByAngle(property){\n\t\tconst{radius,hoverRadio} = this;\n\t\tconst position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);\n\t\treturn `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;\n\t}\n\n\thoverSlice(path,i,flag,e){\n\t\tif(!path) return;\n\t\tconst color = this.colors[i];\n\t\tif(flag) {\n\t\t\ttransform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));\n\t\t\tpath.style.fill = lightenDarkenColor(color, 50);\n\t\t\tlet g_off = getOffset(this.svg);\n\t\t\tlet x = e.pageX - g_off.left + 10;\n\t\t\tlet y = e.pageY - g_off.top - 10;\n\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t\t? this.formatted_labels[i] : this.state.labels[i]) + ': ';\n\t\t\tlet percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);\n\t\t\tthis.tip.setValues(x, y, {name: title, value: percent + \"%\"});\n\t\t\tthis.tip.showTip();\n\t\t} else {\n\t\t\ttransform(path,'translate3d(0,0,0)');\n\t\t\tthis.tip.hideTip();\n\t\t\tpath.style.fill = color;\n\t\t}\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', this.mouseMove);\n\t\tthis.container.addEventListener('mouseleave', this.mouseLeave);\n\t}\n\n\tmouseMove(e){\n\t\tconst target = e.target;\n\t\tlet slices = this.components.get('pieSlices').store;\n\t\tlet prevIndex = this.curActiveSliceIndex;\n\t\tlet prevAcitve = this.curActiveSlice;\n\t\tif(slices.includes(target)) {\n\t\t\tlet i = slices.indexOf(target);\n\t\t\tthis.hoverSlice(prevAcitve, prevIndex,false);\n\t\t\tthis.curActiveSlice = target;\n\t\t\tthis.curActiveSliceIndex = i;\n\t\t\tthis.hoverSlice(target, i, true, e);\n\t\t} else {\n\t\t\tthis.mouseLeave();\n\t\t}\n\t}\n\n\tmouseLeave(){\n\t\tthis.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);\n\t}\n}\n", "import BaseChart from './BaseChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { makeText, heatSquare } from '../utils/draw';\nimport { DAY_NAMES_SHORT, addDays, areInSameMonth, getLastDateInMonth, setDayToSunday, getYyyyMmDd, getWeeksBetween, getMonthName, clone,\n\tNO_OF_MILLIS, NO_OF_YEAR_MONTHS, NO_OF_DAYS_IN_WEEK } from '../utils/date-utils';\nimport { calcDistribution, getMaxCheckpoint } from '../utils/intervals';\nimport { getExtraHeight, getExtraWidth, HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE,\n\tHEATMAP_GUTTER_SIZE } from '../utils/constants';\n\nconst COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;\nconst ROW_HEIGHT = COL_WIDTH;\n// const DAY_INCR = 1;\n\nexport default class Heatmap extends BaseChart {\n\tconstructor(parent, options) {\n\t\tsuper(parent, options);\n\t\tthis.type = 'heatmap';\n\n\t\tthis.countLabel = options.countLabel || '';\n\n\t\tlet validStarts = ['Sunday', 'Monday'];\n\t\tlet startSubDomain = validStarts.includes(options.startSubDomain)\n\t\t\t? options.startSubDomain : 'Sunday';\n\t\tthis.startSubDomainIndex = validStarts.indexOf(startSubDomain);\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.discreteDomains = options.discreteDomains === 0 ? 0 : 1;\n\n\t\tm.paddings.top = ROW_HEIGHT * 3;\n\t\tm.paddings.bottom = 0;\n\t\tm.legendHeight = ROW_HEIGHT * 2;\n\t\tm.baseHeight = ROW_HEIGHT * NO_OF_DAYS_IN_WEEK\n\t\t\t+ getExtraHeight(m);\n\n\t\tlet d = this.data;\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tthis.independentWidth = (getWeeksBetween(d.start, d.end)\n\t\t\t+ spacing) * COL_WIDTH + getExtraWidth(m);\n\t}\n\n\tupdateWidth() {\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tlet noOfWeeks = this.state.noOfWeeks ? this.state.noOfWeeks : 52;\n\t\tthis.baseWidth = (noOfWeeks + spacing) * COL_WIDTH\n\t\t\t+ getExtraWidth(this.measures);\n\t}\n\n\tprepareData(data=this.data) {\n\t\tif(data.start && data.end && data.start > data.end) {\n\t\t\tthrow new Error('Start date cannot be greater than end date.');\n\t\t}\n\n\t\tif(!data.start) {\n\t\t\tdata.start = new Date();\n\t\t\tdata.start.setFullYear( data.start.getFullYear() - 1 );\n\t\t}\n\t\tif(!data.end) { data.end = new Date(); }\n\t\tdata.dataPoints = data.dataPoints || {};\n\n\t\tif(parseInt(Object.keys(data.dataPoints)[0]) > 100000) {\n\t\t\tlet points = {};\n\t\t\tObject.keys(data.dataPoints).forEach(timestampSec => {\n\t\t\t\tlet date = new Date(timestampSec * NO_OF_MILLIS);\n\t\t\t\tpoints[getYyyyMmDd(date)] = data.dataPoints[timestampSec];\n\t\t\t});\n\t\t\tdata.dataPoints = points;\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\n\t\ts.start = clone(this.data.start);\n\t\ts.end = clone(this.data.end);\n\n\t\ts.firstWeekStart = clone(s.start);\n\t\ts.noOfWeeks = getWeeksBetween(s.start, s.end);\n\t\ts.distribution = calcDistribution(\n\t\t\tObject.values(this.data.dataPoints), HEATMAP_DISTRIBUTION_SIZE);\n\n\t\ts.domainConfigs = this.getDomains();\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\t\tlet lessCol = this.discreteDomains ? 0 : 1;\n\n\t\tlet componentConfigs = s.domainConfigs.map((config, i) => [\n\t\t\t'heatDomain',\n\t\t\t{\n\t\t\t\tindex: config.index,\n\t\t\t\tcolWidth: COL_WIDTH,\n\t\t\t\trowHeight: ROW_HEIGHT,\n\t\t\t\tsquareSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\tradius: this.rawChartArgs.radius || 0,\n\t\t\t\txTranslate: s.domainConfigs\n\t\t\t\t\t.filter((config, j) => j < i)\n\t\t\t\t\t.map(config => config.cols.length - lessCol)\n\t\t\t\t\t.reduce((a, b) => a + b, 0)\n\t\t\t\t\t* COL_WIDTH\n\t\t\t},\n\t\t\tfunction() {\n\t\t\t\treturn s.domainConfigs[i];\n\t\t\t}.bind(this)\n\n\t\t]);\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map((args, i) => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0] + '-' + i, component];\n\t\t\t})\n\t\t);\n\n\t\tlet y = 0;\n\t\tDAY_NAMES_SHORT.forEach((dayName, i) => {\n\t\t\tif([1, 3, 5].includes(i)) {\n\t\t\t\tlet dayText = makeText('subdomain-name', -COL_WIDTH/2, y, dayName,\n\t\t\t\t\t{\n\t\t\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\t\t\tdy: 8,\n\t\t\t\t\t\ttextAnchor: 'end'\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tthis.drawArea.appendChild(dayText);\n\t\t\t}\n\t\t\ty += ROW_HEIGHT;\n\t\t});\n\t}\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\n\t\tthis.data = this.prepareData(data);\n\t\tthis.draw();\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tthis.components.forEach(comp => {\n\t\t\t\tlet daySquares = comp.store;\n\t\t\t\tlet daySquare = e.target;\n\t\t\t\tif(daySquares.includes(daySquare)) {\n\n\t\t\t\t\tlet count = daySquare.getAttribute('data-value');\n\t\t\t\t\tlet dateParts = daySquare.getAttribute('data-date').split('-');\n\n\t\t\t\t\tlet month = getMonthName(parseInt(dateParts[1])-1, true);\n\n\t\t\t\t\tlet gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect();\n\n\t\t\t\t\tlet width = parseInt(e.target.getAttribute('width'));\n\t\t\t\t\tlet x = pOff.left - gOff.left + width/2;\n\t\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\t\tlet value = count + ' ' + this.countLabel;\n\t\t\t\t\tlet name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2];\n\n\t\t\t\t\tthis.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);\n\t\t\t\t\tthis.tip.showTip();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\trenderLegend() {\n\t\tthis.legendArea.textContent = '';\n\t\tlet x = 0;\n\t\tlet y = ROW_HEIGHT;\n\t\tlet radius = this.rawChartArgs.radius || 0;\n\n\t\tlet lessText = makeText('subdomain-name', x, y, 'Less',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tx = (COL_WIDTH * 2) + COL_WIDTH/2;\n\t\tthis.legendArea.appendChild(lessText);\n\n\t\tthis.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map((color, i) => {\n\t\t\tconst square = heatSquare('heatmap-legend-unit', x + (COL_WIDTH + 3) * i,\n\t\t\t\ty, HEATMAP_SQUARE_SIZE, radius, color);\n\t\t\tthis.legendArea.appendChild(square);\n\t\t});\n\n\t\tlet moreTextX = x + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH/4;\n\t\tlet moreText = makeText('subdomain-name', moreTextX, y, 'More',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tthis.legendArea.appendChild(moreText);\n\t}\n\n\tgetDomains() {\n\t\tlet s = this.state;\n\t\tconst [startMonth, startYear] = [s.start.getMonth(), s.start.getFullYear()];\n\t\tconst [endMonth, endYear] = [s.end.getMonth(), s.end.getFullYear()];\n\n\t\tconst noOfMonths = (endMonth - startMonth + 1) + (endYear - startYear) * 12;\n\n\t\tlet domainConfigs = [];\n\n\t\tlet startOfMonth = clone(s.start);\n\t\tfor(var i = 0; i < noOfMonths; i++) {\n\t\t\tlet endDate = s.end;\n\t\t\tif(!areInSameMonth(startOfMonth, s.end)) {\n\t\t\t\tlet [month, year] = [startOfMonth.getMonth(), startOfMonth.getFullYear()];\n\t\t\t\tendDate = getLastDateInMonth(month, year);\n\t\t\t}\n\t\t\tdomainConfigs.push(this.getDomainConfig(startOfMonth, endDate));\n\n\t\t\taddDays(endDate, 1);\n\t\t\tstartOfMonth = endDate;\n\t\t}\n\n\t\treturn domainConfigs;\n\t}\n\n\tgetDomainConfig(startDate, endDate='') {\n\t\tlet [month, year] = [startDate.getMonth(), startDate.getFullYear()];\n\t\tlet startOfWeek = setDayToSunday(startDate); // TODO: Monday as well\n\t\tendDate = clone(endDate) || getLastDateInMonth(month, year);\n\n\t\tlet domainConfig = {\n\t\t\tindex: month,\n\t\t\tcols: []\n\t\t};\n\n\t\taddDays(endDate, 1);\n\t\tlet noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate);\n\n\t\tlet cols = [], col;\n\t\tfor(var i = 0; i < noOfMonthWeeks; i++) {\n\t\t\tcol = this.getCol(startOfWeek, month);\n\t\t\tcols.push(col);\n\n\t\t\tstartOfWeek = new Date(col[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd);\n\t\t\taddDays(startOfWeek, 1);\n\t\t}\n\n\t\tif(col[NO_OF_DAYS_IN_WEEK - 1].dataValue !== undefined) {\n\t\t\taddDays(startOfWeek, 1);\n\t\t\tcols.push(this.getCol(startOfWeek, month, true));\n\t\t}\n\n\t\tdomainConfig.cols = cols;\n\n\t\treturn domainConfig;\n\t}\n\n\tgetCol(startDate, month, empty = false) {\n\t\tlet s = this.state;\n\n\t\t// startDate is the start of week\n\t\tlet currentDate = clone(startDate);\n\t\tlet col = [];\n\n\t\tfor(var i = 0; i < NO_OF_DAYS_IN_WEEK; i++, addDays(currentDate, 1)) {\n\t\t\tlet config = {};\n\n\t\t\t// Non-generic adjustment for entire heatmap, needs state\n\t\t\tlet currentDateWithinData = currentDate >= s.start && currentDate <= s.end;\n\n\t\t\tif(empty || currentDate.getMonth() !== month || !currentDateWithinData) {\n\t\t\t\tconfig.yyyyMmDd = getYyyyMmDd(currentDate);\n\t\t\t} else {\n\t\t\t\tconfig = this.getSubDomainConfig(currentDate);\n\t\t\t}\n\t\t\tcol.push(config);\n\t\t}\n\n\t\treturn col;\n\t}\n\n\tgetSubDomainConfig(date) {\n\t\tlet yyyyMmDd = getYyyyMmDd(date);\n\t\tlet dataValue = this.data.dataPoints[yyyyMmDd];\n\t\tlet config = {\n\t\t\tyyyyMmDd: yyyyMmDd,\n\t\t\tdataValue: dataValue || 0,\n\t\t\tfill: this.colors[getMaxCheckpoint(dataValue, this.state.distribution)]\n\t\t};\n\t\treturn config;\n\t}\n}\n", "import BaseChart from './BaseChart';\nimport { dataPrep, zeroDataPrep, getShortenedLabels } from '../utils/axis-chart-utils';\nimport { AXIS_LEGEND_BAR_SIZE } from '../utils/constants';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset, fire } from '../utils/dom';\nimport { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale, getClosestInArray } from '../utils/intervals';\nimport { floatTwo } from '../utils/helpers';\nimport { makeOverlay, updateOverlay, legendBar } from '../utils/draw';\nimport { getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO,\n\tLINE_CHART_DOT_SIZE } from '../utils/constants';\n\nexport default class AxisChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\n\t\tthis.barOptions = args.barOptions || {};\n\t\tthis.lineOptions = args.lineOptions || {};\n\n\t\tthis.type = args.type || 'line';\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures() {\n\t\tif(this.data.datasets.length <= 1) {\n\t\t\tthis.config.showLegend = 0;\n\t\t\tthis.measures.paddings.bottom = 30;\n\t\t}\n\t}\n\n\tconfigure(options) {\n\t\tsuper.configure(options);\n\n\t\toptions.axisOptions = options.axisOptions || {};\n\t\toptions.tooltipOptions = options.tooltipOptions || {};\n\n\t\tthis.config.xAxisMode = options.axisOptions.xAxisMode || 'span';\n\t\tthis.config.yAxisMode = options.axisOptions.yAxisMode || 'span';\n\t\tthis.config.xIsSeries = options.axisOptions.xIsSeries || 0;\n\t\tthis.config.shortenYAxisNumbers = options.axisOptions.shortenYAxisNumbers || 0;\n\n\t\tthis.config.formatTooltipX = options.tooltipOptions.formatTooltipX;\n\t\tthis.config.formatTooltipY = options.tooltipOptions.formatTooltipY;\n\n\t\tthis.config.valuesOverPoints = options.valuesOverPoints;\n\t}\n\n\tprepareData(data=this.data) {\n\t\treturn dataPrep(data, this.type);\n\t}\n\n\tprepareFirstData(data=this.data) {\n\t\treturn zeroDataPrep(data);\n\t}\n\n\tcalc(onlyWidthChange = false) {\n\t\tthis.calcXPositions();\n\t\tif(!onlyWidthChange) {\n\t\t\tthis.calcYAxisParameters(this.getAllYValues(), this.type === 'line');\n\t\t}\n\t\tthis.makeDataByIndex();\n\t}\n\n\tcalcXPositions() {\n\t\tlet s = this.state;\n\t\tlet labels = this.data.labels;\n\t\ts.datasetLength = labels.length;\n\n\t\ts.unitWidth = this.width/(s.datasetLength);\n\t\t// Default, as per bar, and mixed. Only line will be a special case\n\t\ts.xOffset = s.unitWidth/2;\n\n\t\t// // For a pure Line Chart\n\t\t// s.unitWidth = this.width/(s.datasetLength - 1);\n\t\t// s.xOffset = 0;\n\n\t\ts.xAxis = {\n\t\t\tlabels: labels,\n\t\t\tpositions: labels.map((d, i) =>\n\t\t\t\tfloatTwo(s.xOffset + i * s.unitWidth)\n\t\t\t)\n\t\t};\n\t}\n\n\tcalcYAxisParameters(dataValues, withMinimum = 'false') {\n\t\tconst yPts = calcChartIntervals(dataValues, withMinimum);\n\t\tconst scaleMultiplier = this.height / getValueRange(yPts);\n\t\tconst intervalHeight = getIntervalSize(yPts) * scaleMultiplier;\n\t\tconst zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight);\n\n\t\tthis.state.yAxis = {\n\t\t\tlabels: yPts,\n\t\t\tpositions: yPts.map(d => zeroLine - d * scaleMultiplier),\n\t\t\tscaleMultiplier: scaleMultiplier,\n\t\t\tzeroLine: zeroLine,\n\t\t};\n\n\t\t// Dependent if above changes\n\t\tthis.calcDatasetPoints();\n\t\tthis.calcYExtremes();\n\t\tthis.calcYRegions();\n\t}\n\n\tcalcDatasetPoints() {\n\t\tlet s = this.state;\n\t\tlet scaleAll = values => values.map(val => scale(val, s.yAxis));\n\n\t\ts.datasets = this.data.datasets.map((d, i) => {\n\t\t\tlet values = d.values;\n\t\t\tlet cumulativeYs = d.cumulativeYs || [];\n\t\t\treturn {\n\t\t\t\tname: d.name && d.name.replace(/<|>|&/g, (char) => char == '&' ? '&' : char == '<' ? '<' : '>'),\n\t\t\t\tindex: i,\n\t\t\t\tchartType: d.chartType,\n\n\t\t\t\tvalues: values,\n\t\t\t\tyPositions: scaleAll(values),\n\n\t\t\t\tcumulativeYs: cumulativeYs,\n\t\t\t\tcumulativeYPos: scaleAll(cumulativeYs),\n\t\t\t};\n\t\t});\n\t}\n\n\tcalcYExtremes() {\n\t\tlet s = this.state;\n\t\tif(this.barOptions.stacked) {\n\t\t\ts.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos;\n\t\t\treturn;\n\t\t}\n\t\ts.yExtremes = new Array(s.datasetLength).fill(9999);\n\t\ts.datasets.map(d => {\n\t\t\td.yPositions.map((pos, j) => {\n\t\t\t\tif(pos < s.yExtremes[j]) {\n\t\t\t\t\ts.yExtremes[j] = pos;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tcalcYRegions() {\n\t\tlet s = this.state;\n\t\tif(this.data.yMarkers) {\n\t\t\tthis.state.yMarkers = this.data.yMarkers.map(d => {\n\t\t\t\td.position = scale(d.value, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\t// if(!d.label.includes(':')) {\n\t\t\t\t// \td.label += ': ' + d.value;\n\t\t\t\t// }\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.state.yRegions = this.data.yRegions.map(d => {\n\t\t\t\td.startPos = scale(d.start, s.yAxis);\n\t\t\t\td.endPos = scale(d.end, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t}\n\n\tgetAllYValues() {\n\t\tlet key = 'values';\n\n\t\tif(this.barOptions.stacked) {\n\t\t\tkey = 'cumulativeYs';\n\t\t\tlet cumulative = new Array(this.state.datasetLength).fill(0);\n\t\t\tthis.data.datasets.map((d, i) => {\n\t\t\t\tlet values = this.data.datasets[i].values;\n\t\t\t\td[key] = cumulative = cumulative.map((c, i) => c + values[i]);\n\t\t\t});\n\t\t}\n\n\t\tlet allValueLists = this.data.datasets.map(d => d[key]);\n\t\tif(this.data.yMarkers) {\n\t\t\tallValueLists.push(this.data.yMarkers.map(d => d.value));\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.data.yRegions.map(d => {\n\t\t\t\tallValueLists.push([d.end, d.start]);\n\t\t\t});\n\t\t}\n\n\t\treturn [].concat(...allValueLists);\n\t}\n\n\tsetupComponents() {\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'yAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.yAxisMode,\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tshortenNumbers: this.config.shortenYAxisNumbers\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'xAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.xAxisMode,\n\t\t\t\t\theight: this.height,\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\ts.xAxis.calcLabels = getShortenedLabels(this.width,\n\t\t\t\t\t\ts.xAxis.labels, this.config.xIsSeries);\n\n\t\t\t\t\treturn s.xAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'yRegions',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yRegions;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\t\t];\n\n\t\tlet barDatasets = this.state.datasets.filter(d => d.chartType === 'bar');\n\t\tlet lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');\n\n\t\tlet barsConfigs = barDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'barGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tstacked: this.barOptions.stacked,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t\tminHeight: this.height * MIN_BAR_PERCENT_HEIGHT,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet stacked = this.barOptions.stacked;\n\n\t\t\t\t\tlet spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO;\n\t\t\t\t\tlet barsWidth = s.unitWidth * (1 - spaceRatio);\n\t\t\t\t\tlet barWidth = barsWidth/(stacked ? 1 : barDatasets.length);\n\n\t\t\t\t\tlet xPositions = s.xAxis.positions.map(x => x - barsWidth/2);\n\t\t\t\t\tif(!stacked) {\n\t\t\t\t\t\txPositions = xPositions.map(p => p + barWidth * index);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet labels = new Array(s.datasetLength).fill('');\n\t\t\t\t\tif(this.config.valuesOverPoints) {\n\t\t\t\t\t\tif(stacked && d.index === s.datasets.length - 1) {\n\t\t\t\t\t\t\tlabels = d.cumulativeYs;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlabels = d.values;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet offsets = new Array(s.datasetLength).fill(0);\n\t\t\t\t\tif(stacked) {\n\t\t\t\t\t\toffsets = d.yPositions.map((y, j) => y - d.cumulativeYPos[j]);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: xPositions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\t\t\t\t\t\toffsets: offsets,\n\t\t\t\t\t\t// values: d.values,\n\t\t\t\t\t\tlabels: labels,\n\n\t\t\t\t\t\tzeroLine: s.yAxis.zeroLine,\n\t\t\t\t\t\tbarsWidth: barsWidth,\n\t\t\t\t\t\tbarWidth: barWidth,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet lineConfigs = lineDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'lineGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tsvgDefs: this.svgDefs,\n\t\t\t\t\theatline: this.lineOptions.heatline,\n\t\t\t\t\tregionFill: this.lineOptions.regionFill,\n\t\t\t\t\tspline: this.lineOptions.spline,\n\t\t\t\t\thideDots: this.lineOptions.hideDots,\n\t\t\t\t\thideLine: this.lineOptions.hideLine,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet minLine = s.yAxis.positions[0] < s.yAxis.zeroLine\n\t\t\t\t\t\t? s.yAxis.positions[0] : s.yAxis.zeroLine;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xAxis.positions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\n\t\t\t\t\t\tvalues: d.values,\n\n\t\t\t\t\t\tzeroLine: minLine,\n\t\t\t\t\t\tradius: this.lineOptions.dotSize || LINE_CHART_DOT_SIZE,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet markerConfigs = [\n\t\t\t[\n\t\t\t\t'yMarkers',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yMarkers;\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tcomponentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);\n\n\t\tlet optionals = ['yMarkers', 'yRegions'];\n\t\tthis.dataUnitComponents = [];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.filter(args => !optionals.includes(args[0]) || this.state[args[0]])\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\tif(args[0].includes('lineGraph') || args[0].includes('barGraph')) {\n\t\t\t\t\tthis.dataUnitComponents.push(component);\n\t\t\t\t}\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tmakeDataByIndex() {\n\t\tthis.dataByIndex = {};\n\n\t\tlet s = this.state;\n\t\tlet formatX = this.config.formatTooltipX;\n\t\tlet formatY = this.config.formatTooltipY;\n\t\tlet titles = s.xAxis.labels;\n\n\t\ttitles.map((label, index) => {\n\t\t\tlet values = this.state.datasets.map((set, i) => {\n\t\t\t\tlet value = set.values[index];\n\t\t\t\treturn {\n\t\t\t\t\ttitle: set.name,\n\t\t\t\t\tvalue: value,\n\t\t\t\t\tyPos: set.yPositions[index],\n\t\t\t\t\tcolor: this.colors[i],\n\t\t\t\t\tformatted: formatY ? formatY(value) : value,\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tthis.dataByIndex[index] = {\n\t\t\t\tlabel: label,\n\t\t\t\tformattedLabel: formatX ? formatX(label) : label,\n\t\t\t\txPos: s.xAxis.positions[index],\n\t\t\t\tvalues: values,\n\t\t\t\tyExtreme: s.yExtremes[index],\n\t\t\t};\n\t\t});\n\t}\n\n\tbindTooltip() {\n\t\t// NOTE: could be in tooltip itself, as it is a given functionality for its parent\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet m = this.measures;\n\t\t\tlet o = getOffset(this.container);\n\t\t\tlet relX = e.pageX - o.left - getLeftOffset(m);\n\t\t\tlet relY = e.pageY - o.top;\n\n\t\t\tif(relY < this.height + getTopOffset(m)\n\t\t\t\t&& relY > getTopOffset(m)) {\n\t\t\t\tthis.mapTooltipXPosition(relX);\n\t\t\t} else {\n\t\t\t\tthis.tip.hideTip();\n\t\t\t}\n\t\t});\n\t}\n\n\tmapTooltipXPosition(relX) {\n\t\tlet s = this.state;\n\t\tif(!s.yExtremes) return;\n\n\t\tlet index = getClosestInArray(relX, s.xAxis.positions, true);\n\t\tif (index >= 0) {\n\t\t\tlet dbi = this.dataByIndex[index];\n\n\t\t\tthis.tip.setValues(\n\t\t\t\tdbi.xPos + this.tip.offset.x,\n\t\t\t\tdbi.yExtreme + this.tip.offset.y,\n\t\t\t\t{name: dbi.formattedLabel, value: ''},\n\t\t\t\tdbi.values,\n\t\t\t\tindex\n\t\t\t);\n\n\t\t\tthis.tip.showTip();\n\t\t}\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.data;\n\t\tif(s.datasets.length > 1) {\n\t\t\tthis.legendArea.textContent = '';\n\t\t\ts.datasets.map((d, i) => {\n\t\t\t\tlet barWidth = AXIS_LEGEND_BAR_SIZE;\n\t\t\t\t// let rightEndPoint = this.baseWidth - this.measures.margins.left - this.measures.margins.right;\n\t\t\t\t// let multiplier = s.datasets.length - i;\n\t\t\t\tlet rect = legendBar(\n\t\t\t\t\t// rightEndPoint - multiplier * barWidth,\t// To right align\n\t\t\t\t\tbarWidth * i,\n\t\t\t\t\t'0',\n\t\t\t\t\tbarWidth,\n\t\t\t\t\tthis.colors[i],\n\t\t\t\t\td.name,\n\t\t\t\t\tthis.config.truncateLegends);\n\t\t\t\tthis.legendArea.appendChild(rect);\n\t\t\t});\n\t\t}\n\t}\n\n\n\n\t// Overlay\n\tmakeOverlay() {\n\t\tif(this.init) {\n\t\t\tthis.init = 0;\n\t\t\treturn;\n\t\t}\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\n\t\tthis.overlayGuides = this.dataUnitComponents.map(c => {\n\t\t\treturn {\n\t\t\t\ttype: c.unitType,\n\t\t\t\toverlay: undefined,\n\t\t\t\tunits: c.units,\n\t\t\t};\n\t\t});\n\n\t\tif(this.state.currentIndex === undefined) {\n\t\t\tthis.state.currentIndex = this.state.datasetLength - 1;\n\t\t}\n\n\t\t// Render overlays\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\n\t\t\td.overlay = makeOverlay[d.type](currentUnit);\n\t\t\tthis.drawArea.appendChild(d.overlay);\n\t\t});\n\t}\n\n\tupdateOverlayGuides() {\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\t}\n\n\tbindOverlay() {\n\t\tthis.parent.addEventListener('data-select', () => {\n\t\t\tthis.updateOverlay();\n\t\t});\n\t}\n\n\tbindUnits() {\n\t\tthis.dataUnitComponents.map(c => {\n\t\t\tc.units.map(unit => {\n\t\t\t\tunit.addEventListener('click', () => {\n\t\t\t\t\tlet index = unit.getAttribute('data-point-index');\n\t\t\t\t\tthis.setCurrentDataPoint(index);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\t// Note: Doesn't work as tooltip is absolutely positioned\n\t\tthis.tip.container.addEventListener('click', () => {\n\t\t\tlet index = this.tip.container.getAttribute('data-point-index');\n\t\t\tthis.setCurrentDataPoint(index);\n\t\t});\n\t}\n\n\tupdateOverlay() {\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\t\t\tupdateOverlay[d.type](currentUnit, d.overlay);\n\t\t});\n\t}\n\n\tonLeftArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex - 1);\n\t}\n\n\tonRightArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex + 1);\n\t}\n\n\tgetDataPoint(index=this.state.currentIndex) {\n\t\tlet s = this.state;\n\t\tlet data_point = {\n\t\t\tindex: index,\n\t\t\tlabel: s.xAxis.labels[index],\n\t\t\tvalues: s.datasets.map(d => d.values[index])\n\t\t};\n\t\treturn data_point;\n\t}\n\n\tsetCurrentDataPoint(index) {\n\t\tlet s = this.state;\n\t\tindex = parseInt(index);\n\t\tif(index < 0) index = 0;\n\t\tif(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1;\n\t\tif(index === s.currentIndex) return;\n\t\ts.currentIndex = index;\n\t\tfire(this.parent, \"data-select\", this.getDataPoint());\n\t}\n\n\n\n\t// API\n\taddDataPoint(label, datasetValues, index=this.state.datasetLength) {\n\t\tsuper.addDataPoint(label, datasetValues, index);\n\t\tthis.data.labels.splice(index, 0, label);\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\td.values.splice(index, 0, datasetValues[i]);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tremoveDataPoint(index = this.state.datasetLength-1) {\n\t\tif (this.data.labels.length <= 1) {\n\t\t\treturn;\n\t\t}\n\t\tsuper.removeDataPoint(index);\n\t\tthis.data.labels.splice(index, 1);\n\t\tthis.data.datasets.map(d => {\n\t\t\td.values.splice(index, 1);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tupdateDataset(datasetValues, index=0) {\n\t\tthis.data.datasets[index].values = datasetValues;\n\t\tthis.update(this.data);\n\t}\n\t// addDataset(dataset, index) {}\n\t// removeDataset(index = 0) {}\n\n\tupdateDatasets(datasets) {\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\tif(datasets[i]) {\n\t\t\t\td.values = datasets[i];\n\t\t\t}\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\t// updateDataPoint(dataPoint, index = 0) {}\n\t// addDataPoint(dataPoint, index = 0) {}\n\t// removeDataPoint(index = 0) {}\n}\n", "import AggregationChart from './AggregationChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset } from '../utils/dom';\nimport { getPositionByAngle } from '../utils/helpers';\nimport { makeArcStrokePathStr, makeStrokeCircleStr } from '../utils/draw';\nimport { lightenDarkenColor } from '../utils/colors';\nimport { transform } from '../utils/animation';\nimport { FULL_ANGLE } from '../utils/constants';\n\nexport default class DonutChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'donut';\n\t\tthis.initTimeout = 0;\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\t\tthis.mouseMove = this.mouseMove.bind(this);\n\t\tthis.mouseLeave = this.mouseLeave.bind(this);\n\n\t\tthis.hoverRadio = args.hoverRadio || 0.1;\n\t\tthis.config.startAngle = args.startAngle || 0;\n\n\t\tthis.clockWise = args.clockWise || false;\n\t\tthis.strokeWidth = args.strokeWidth || 30;\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\t\tthis.radius =\n\t\t\tthis.height > this.width\n\t\t\t\t? this.center.x - this.strokeWidth / 2\n\t\t\t\t: this.center.y - this.strokeWidth / 2;\n\n\t\tconst { radius, clockWise } = this;\n\n\t\tconst prevSlicesProperties = s.slicesProperties || [];\n\t\ts.sliceStrings = [];\n\t\ts.slicesProperties = [];\n\t\tlet curAngle = 180 - this.config.startAngle;\n\n\t\ts.sliceTotals.map((total, i) => {\n\t\t\tconst startAngle = curAngle;\n\t\t\tconst originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;\n\t\t\tconst largeArc = originDiffAngle > 180 ? 1: 0;\n\t\t\tconst diffAngle = clockWise ? -originDiffAngle : originDiffAngle;\n\t\t\tconst endAngle = curAngle = curAngle + diffAngle;\n\t\t\tconst startPosition = getPositionByAngle(startAngle, radius);\n\t\t\tconst endPosition = getPositionByAngle(endAngle, radius);\n\n\t\t\tconst prevProperty = this.init && prevSlicesProperties[i];\n\n\t\t\tlet curStart,curEnd;\n\t\t\tif(this.init) {\n\t\t\t\tcurStart = prevProperty ? prevProperty.startPosition : startPosition;\n\t\t\t\tcurEnd = prevProperty ? prevProperty.endPosition : startPosition;\n\t\t\t} else {\n\t\t\t\tcurStart = startPosition;\n\t\t\t\tcurEnd = endPosition;\n\t\t\t}\n\t\t\tconst curPath =\n\t\t\t\toriginDiffAngle === 360\n\t\t\t\t\t? makeStrokeCircleStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc)\n\t\t\t\t\t: makeArcStrokePathStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc);\n\n\t\t\ts.sliceStrings.push(curPath);\n\t\t\ts.slicesProperties.push({\n\t\t\t\tstartPosition,\n\t\t\t\tendPosition,\n\t\t\t\tvalue: total,\n\t\t\t\ttotal: s.grandTotal,\n\t\t\t\tstartAngle,\n\t\t\t\tendAngle,\n\t\t\t\tangle: diffAngle\n\t\t\t});\n\n\t\t});\n\t\tthis.init = 0;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'donutSlices',\n\t\t\t\t{ },\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsliceStrings: s.sliceStrings,\n\t\t\t\t\t\tcolors: this.colors,\n\t\t\t\t\t\tstrokeWidth: this.strokeWidth,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalTranslateByAngle(property){\n\t\tconst{ radius, hoverRadio } = this;\n\t\tconst position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);\n\t\treturn `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;\n\t}\n\n\thoverSlice(path,i,flag,e){\n\t\tif(!path) return;\n\t\tconst color = this.colors[i];\n\t\tif(flag) {\n\t\t\ttransform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));\n\t\t\tpath.style.stroke = lightenDarkenColor(color, 50);\n\t\t\tlet g_off = getOffset(this.svg);\n\t\t\tlet x = e.pageX - g_off.left + 10;\n\t\t\tlet y = e.pageY - g_off.top - 10;\n\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t\t? this.formatted_labels[i] : this.state.labels[i]) + ': ';\n\t\t\tlet percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);\n\t\t\tthis.tip.setValues(x, y, {name: title, value: percent + \"%\"});\n\t\t\tthis.tip.showTip();\n\t\t} else {\n\t\t\ttransform(path,'translate3d(0,0,0)');\n\t\t\tthis.tip.hideTip();\n\t\t\tpath.style.stroke = color;\n\t\t}\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', this.mouseMove);\n\t\tthis.container.addEventListener('mouseleave', this.mouseLeave);\n\t}\n\n\tmouseMove(e){\n\t\tconst target = e.target;\n\t\tlet slices = this.components.get('donutSlices').store;\n\t\tlet prevIndex = this.curActiveSliceIndex;\n\t\tlet prevAcitve = this.curActiveSlice;\n\t\tif(slices.includes(target)) {\n\t\t\tlet i = slices.indexOf(target);\n\t\t\tthis.hoverSlice(prevAcitve, prevIndex,false);\n\t\t\tthis.curActiveSlice = target;\n\t\t\tthis.curActiveSliceIndex = i;\n\t\t\tthis.hoverSlice(target, i, true, e);\n\t\t} else {\n\t\t\tthis.mouseLeave();\n\t\t}\n\t}\n\n\tmouseLeave(){\n\t\tthis.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);\n\t}\n}\n"], - "mappings": ";;;AAAA,qBAAqB,IAAK,GAAA;AAAA,EACnB,MADmB,UACF,KAAA;AACtB,MAAI,IAAW,EAAI;AAEnB,MAAK,MAA2B,AAAA,OAAb,YAAa,aAAhC;AAEA,QAAI,IAAO,SAAS,QAAQ,SAAS,qBAAqB,QAAQ,IAC9D,IAAQ,SAAS,cAAc;AACnC,MAAM,OAAO,YAEI,AAAb,MAAa,SACX,EAAK,aACP,EAAK,aAAa,GAAO,EAAK,cAKhC,EAAK,YAAY,IAGf,EAAM,aACR,EAAM,WAAW,UAAU,KAE3B,EAAM,YAAY,SAAS,eAAe;;;ACvB9C,WAAkB,IAAM,GAAA;AAAA,SACA,AAAA,OAAT,MAAS,WAAW,MAAO,UAAU,cAAc,MAAQ,MAAQ;;AA4ClF,mBAA0B,IAAA;AAAA,MACrB,IAAO,GAAQ;AAAA,SAAA,EAAA,KAKb,EAAK,MAAO,UAAS,gBAAgB,aAAa,SAAS,KAAK,YAAA,MAC/D,EAAK,OAAQ,UAAS,gBAAgB,cAAc,SAAS,KAAK;;AAO1E,kBAAyB,IAAA;AAAA,SACI,AAApB,GAAG,iBAAiB;;AAG7B,6BAAoC,IAAA;AAAA,MAE/B,IAAO,GAAG;AAAA,SAGb,EAAK,OAAO,KACN,EAAK,QAAQ,KACb,EAAK,UAAW,QAAO,eAAe,SAAS,gBAAgB,iBAAA,EAC1D,SAAU,QAAO,cAAc,SAAS,gBAAgB;;AAIrE,gCAAuC,IAAA;AAAA,MAClC,IAAS,OAAO,iBAAiB,KACjC,IAAU,WAAW,EAAO,eAC/B,WAAW,EAAO;AAAA,SAEZ,GAAQ,cAAc;;AA2B9B,cAAqB,IAAQ,GAAM,GAAA;AAAA,MAC9B,IAAM,SAAS,YAAY;AAAA,IAE3B,UAAU,GAAA,MAAM;AAAM,WAEjB,KAAK;AAAA,MACT,KAAK,EAAW;AAAA,SAGd,GAAO,cAAc;;AC7E7B,sBAA6B,IAAA;AAAA,SACrB,GAAE,cAAc,GAAE,QAAQ,MAAM,GAAE,SAAS;;AAGnD,uBAA8B,IAAA;AAAA,SACtB,GAAE,QAAQ,OAAO,GAAE,SAAS;;AAGpC,wBAA+B,IAAA;AAAA,SACP,GAAE,QAAQ,MAAM,GAAE,QAAQ,SAC9C,GAAE,SAAS,MAAM,GAAE,SAAS,SAC5B,GAAE,cAAc,GAAE;;AAItB,uBAA8B,IAAA;AAAA,SACP,GAAE,QAAQ,OAAO,GAAE,QAAQ,QAC9C,GAAE,SAAS,OAAO,GAAE,SAAS;;AAAA,2BAAA,IAAA,GAAA;AAAA,MAAA,CAAA,eAAA;AAAA,UAAA,IAAA,UAAA;;AClDjC,kBAAyB,IAAA;AAAA,SACjB,WAAW,GAAE,QAAQ;;AAyC7B,mBAA0B,IAAO,GAAO,GAAA;AAAA,MAAS,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA;AAC5C,OAAA,KACO,IAAQ,GAAM,KAAK,GAAM,GAAM,SAAS;AAAA,MAE/C,IAAc,IAAI,MAAM,KAAK,IAAI,IAAQ,KAAK;AAAA,SAAA,KAC1C,IAAQ,EAAY,OAAO,MAAS,GAAM,OAAO;;AAS1D,wBAA+B,IAAQ,GAAA;AAAA,SAC9B,MAAO,IAAI,SAAS;;AAyB7B,4BAAmC,IAAO,GAAA;AAAA,SAAA,EAAA,GAErC,KAAK,IAAI,KAAQ,eAAe,GAAA,GAChC,KAAK,IAAI,KAAQ,eAAe;;AASrC,uBAA8B,IAAA;AAAA,MAAW,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA;AAAA,SAAA,CACpC,OAAO,MAAM,OAAA,CACR,OADQ,UACR,EAAA,CACC,OAAO,SAAS,OAAA,CACjB,MAAe,KAAY;;AAQrC,eAAsB,IAAA;AAAA,SAGd,OAAO,KAAK,MAAM,KAAI,QAAQ;;AAOrC,mBAA0B,IAAA;AAAA,MACtB,IAAA,QAAQ,IAAA,QAAO,IAAA;AAAA,MAEf,cAAqB;AAAA,WAChB,IAAI,KAAK,GAAU;AAAA,MAGH,AAAA,CAAd,OAAc,SAAd,cAAA,UAAA,SAAc,YAA0B,AAAd,OAAc;AAAd,WAC5B;AAAA,MAGA,MAAM,QAAQ,MAAA,KAAA;AAAA,OAElB,KAAO;AAAA,QACF,GAAU,IAAA,EAEX,KAAO,UAAU;AAAA,SAGnB;;AAAA,8BC3I6B,IAAM,GAAA;AAAA,MACtC,IAAA,QAAQ,IAAA;AAAA,SACR,MAAQ,IAAA,KACF,IAAW,IAAA,IAChB,MAAA,KAEK,KAAO,GAAA,IACZ,IAAA,CAGG,GAAQ;;AAGjB,8BAAqC,IAAQ,GAAA;AAAA,MAC5C,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAa,EAAO,SAAS,GAAO;AAAA,SAGjC,IAAa,IAAA,KACN,UAAU,IAAQ,KAAA,IAElB,UAAU,GAAQ,IAAA,CAEpB,IAAQ;;AAGjB,wBAA+B,IAAK,GAAA;AAAA,MAC9B;AAAA,WAGD,GAAI,SAAS,IACT,GAAI,MAAM,GAAG,IAAI,KAAK,QAEtB;;AAIT,4BAAmC,IAAA;AAAA,MAC9B,IAAA;AAAA,MACiB,AAAA,OAAV,MAAU;AAAU,QAAS;WACd,AAAA,OAAV,MAAU,YAAV,KACN,OAAO,KACZ,OAAO,MAAM;AAAS,WAAO;AAAA,MAI9B,IAAI,KAAK,MAAM,KAAK,MAAM,KAAK,IAAI;AAAA,MACnC,KAAK;AAAG,WAAO;AAAA,MACf,IAAI,KAAK,MAAM,IAAI,IACnB,IAAa,KAAK,IAAI,IAAI,IAAQ,IAAJ,KAAA,CAAW,KAAS,KAAK,IAAI,IAAI,IAAI,QAAQ;AAAA,SAGxE,KAAK,MAAgB,MAAV,KAAe,MAAM,MAAA,CAAO,IAAI,KAAK,KAAK,KAAK,KAAK;;AAIvE,iCAAwC,IAAO,GAAA;AAAA,WAE1C,IAAA,IACI,IAAE,GAAE,IAAE,GAAM,QAAO;AAAA,MACnB,KAAA,CAAM,GAAM,IAAI,EAAM;AAAA,MAI1B,IAAO,SAAC,IAAQ,IAAA;AAAA,QACf,KAAU,GAAO,KAAK,GAAO,IAC7B,KAAU,GAAO,KAAK,GAAO;AAAA,WAAA,EAAA,QAExB,KAAK,KAAK,KAAK,IAAI,IAAS,KAAK,KAAK,IAAI,IAAS,KAAA,OACpD,KAAK,MAAM,IAAS;KAIzB,IAAe,SAAC,IAAS,IAAU,IAAM,IAAA;AAAA,QAGxC,KAAI,EAFA,MAAY,IACZ,MAAQ,KAEZ,IAAQ,GAAE,QAAS,MAAU,KAAK,KAAK,IACvC,IAfW,MAeF,GAAE;AAAA,WAAA,CACP,GAAQ,KAAK,KAAK,IAAI,KAAS,GAC/B,GAAQ,KAAK,KAAK,IAAI,KAAS;;AAAA,SAUzB,SAAC,IAAQ,IAAA;AAAA,WAChB,GAAO,OAAO,SAAC,IAAK,IAAO,IAAG,IAAA;AAAA,aAAY,AAAN,OAAM,IAC3C,GAAM,KAAA,MAAM,GAAM,KAClB,KAAA,MAAO,GAAQ,IAAO,IAAG;OAAM;IAGtB,GAZI,SAAC,IAAO,IAAG,IAAA;AAAA,QAC1B,KAAM,EAAa,GAAE,KAAI,IAAI,GAAE,KAAI,IAAI,KACvC,KAAM,EAAa,IAAO,GAAE,KAAI,IAAI,GAAE,KAAI,IAAA;AAAI,WAAA,OACtC,GAAI,KAAA,MAAM,GAAI,KAAA,MAAM,GAAI,KAAA,MAAM,GAAI,KAAA,MAAM,GAAM,KAAA,MAAM,GAAM;;;ACvExE,oBAAoB,IAAA;AAAA,SACf,KAAI,MAAY,MACX,KAAI,IAAU,IAChB;;AAGR,4BAAmC,IAAO,GAAA;AAAA,MACrC,IAAM,SAAS,KACf,IAAA;AACU,EAAV,EAAI,MAAM,OAAN,KACD,EAAI,MAAM,IAAA,IAAA;AACL,MAER,IAAM,SAAS,GAAI,KACnB,IAAI,WAAY,MAAO,MAAM,IAC7B,IAAI,WAAa,MAAO,IAAK,OAAU,IACvC,IAAI,WAAkB,OAAN,KAAkB;AAAA,SAC9B,KAAS,MAAI,MAAO,KAAK,KAAK,IAAM,KAAK,IAAK,SAAS;;AAGhE,sBAA6B,IAAA;AAAA,MAGxB,IAAS;AAAA,SADA,uCAEC,KAAK,OAAW,EAAO,KAAK;;AC7B3C,aAAW,IAAM,GAAA;AAAA,SACO,AAAA,OAAT,MAAS,WAAW,MAAO,UAAU,cAAc,MAAQ,MAAQ;;AAGlF,mBAA0B,IAAK,GAAA;AAAA,MAC1B,IAAU,SAAS,gBAAgB,8BAA8B;AAAA,WAE5D,KAAK,GAAG;AAAA,QACZ,IAAM,EAAE;AAAA,QAEF,AAAN,MAAM;AAAN,UACD,GAAK,YAAY;aAEL,AAAN,MAAM,UAAU;AAAA,UACpB,IAAM,IAAE;AAAA,QACR,WAAW,aAAa,GAAS,IAAA,EAC7B,YAAY;;AAEJ,MAAN,MAAM,WACE,AAAA,CAAR,MAAQ,SAAR,cAAA,UAAA,QAAQ,YAAR,OACF,KAAK,GAAK,IAAI,SAAA,IAAA;AAAA,UACZ,MAAM,MAAQ,EAAI;WAInB,CAAN,MAAM,eAAN,KAAyB,UACnB,AAAN,MAAM,cAAN,EACF,cAAyB,IAAA,EAEjB,aAAa,GAAG;;AAAA,SAKpB;;AAGR,gCAAgC,IAAY,GAAA;AAAA,SACpC,UAAU,kBAAA,EAAA,QACR,IAAA,IACJ,GAAA,IACA,GAAA,IACA,GAAA,IACA,GAAA,IACA;;AAIN,yBAAyB,IAAU,GAAQ,GAAO,GAAA;AAAA,SAC1C,UAAU,QAAA,EAAA,QACN,IAAA,OAAA,iBACc,GAAA,QACd,GAAA,gBACM;;AAIlB,0BAAiC,IAAQ,GAAW,GAAO,GAAA;AAAA,SACnD,UAAU,OAAA,EAAA,WACL,GAAA,QACH,IAAA,OACD,GAAA,QACC;;AAIV,qBAA4B,IAAA;AAAA,SACpB,UAAU,QAAA,EAAA,QACR;;AAIV,sBAA6B,IAAA;AAAA,MAAW,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAU,IAAI,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,QACjD,IAAA,EAAA,WACQ,IAAA,WACA;AAAA,SAET,KAAQ,GAAK,SAAS,IAClB,UAAU,KAAK;;AAWvB,kBAAyB,IAAA;AAAA,SACjB,UAAU,QAAA,EAAA,WAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAD0B,IAAA,GAGvC,IAAA,QAAA,EAAA,QAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAHkD,QAAA,MAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAa,QAAA,gBAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAoB;;AAYxF,wBAA+B,IAAe,GAAa,GAAQ,GAAA;AAAA,MAAQ,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAU,GAAG,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAS,GAC3F,IAAyB,EAAO,IAAI,GAAc,GAAvC,IAA0C,EAAO,IAAI,GAAc,GAC9E,IAAqB,EAAO,IAAI,EAAY,GAAnC,IAAsC,EAAO,IAAI,EAAY;AAAA,SAAA,MAChE,EAAO,IAAA,MAAK,EAAO,IAAA,UAC1B,IAAA,MAAa,IAAA,WACZ,IAAA,MAAU,IAAA,QAAY,IAAA,MAAY,KAAY,IAAI,KAAA,SACpD,IAAA,MAAW,IAAA;;AAGf,uBAA8B,IAAe,GAAa,GAAQ,GAAA;AAAA,MAAQ,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAU,GAAG,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAS,GAC1F,IAAyB,EAAO,IAAI,GAAc,GAAvC,IAA0C,EAAO,IAAI,GAAc,GAC9E,IAA6B,EAAO,IAAI,EAAY,GAA3C,IAAyD,IAAX,EAAO,GAA7C,IAAoD,EAAO,IAAI,EAAY;AAAA,SAAA,MACtF,EAAO,IAAA,MAAK,EAAO,IAAA,UAC1B,IAAA,MAAa,IAAA,WACZ,IAAA,MAAU,IAAA,QAAY,IAAA,MAAY,KAAY,IAAI,KAAA,SACpD,IAAA,MAAW,IAAA,YACV,IAAA,MAAa,IAAA,WACZ,IAAA,MAAU,IAAA,QAAY,IAAA,MAAY,KAAY,IAAI,KAAA,SACpD,IAAA,MAAW,IAAA;;AAGf,8BAAqC,IAAe,GAAa,GAAQ,GAAA;AAAA,MAAQ,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAU,GAAG,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAS,GACjG,IAAyB,EAAO,IAAI,GAAc,GAAvC,IAA0C,EAAO,IAAI,GAAc,GAC9E,IAAqB,EAAO,IAAI,EAAY,GAAnC,IAAsC,EAAO,IAAI,EAAY;AAAA,SAAA,MAEhE,IAAA,MAAa,IAAA,WACnB,IAAA,MAAU,IAAA,QAAY,IAAA,MAAY,KAAY,IAAI,KAAA,SACpD,IAAA,MAAW;;AAGf,6BAAoC,IAAe,GAAa,GAAQ,GAAA;AAAA,MAAQ,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAU,GAAG,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAS,GAChG,IAAyB,EAAO,IAAI,GAAc,GAAvC,IAA0C,EAAO,IAAI,GAAc,GAC9E,IAA6B,EAAO,IAAI,EAAY,GAA3C,IAAuD,IAAT,IAAa,GAAnD,IAA8D,EAAO,IAAI,GAAc;AAAA,SAAA,MAElG,IAAA,MAAa,IAAA,WACnB,IAAA,MAAU,IAAA,QAAY,IAAA,MAAY,KAAY,IAAI,KAAA,SACpD,IAAA,MAAW,IAAA,UACV,IAAA,MAAa,IAAA,WACZ,IAAA,MAAU,IAAA,QAAY,IAAA,MAAY,KAAY,IAAI,KAAA,SACpD,IAAA,MAAW;;AAGf,sBAA6B,IAAY,GAAA;AAAA,MAAO,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA,IAC3C,IAAY,wBAA6B,IAAQ,MAAM,KAAU,YAAY,YAC7E,IAAc,uBAAuB,IAAY,IACjD,IAAA,CAAa,GAAG,KAAK;AAAA,SACtB,KAAA,KAAA,CACW,KAAK,KAAK,KAAA,gBAGR,GAAa,MAAM,GAAO,EAAU,KAAA,gBACpC,GAAa,OAAO,GAAO,EAAU,KAAA,gBACrC,GAAa,QAAQ,GAAO,EAAU,KAE/C;;AAGR,uBAA8B,IAAG,GAAG,GAAO,GAAA;AAAA,MAC1C,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAM,8BAA8B,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAK;AAAA,SAkBlC,UAAU,QAAA,EAAA,WAfL,kBAAA,GACR,IAAA,GACA,GAAA,OACI,GAAA,QACC,GAAA,MACF,GAAA,QAAA,EAAA,QAEK,mBAAmB,GAAA,MAAO,oBAAA,QAGV,KAAS,KAAA,OAAU,IAAA,OAAU,GAAA,gBACvC;;AAOnB,oBAA2B,IAAW,GAAG,GAAG,GAAM,GAAA;AAAA,MAAQ,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAK,QAAQ,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAClE,IAAA,EAAA,WACQ,IAAA,GACR,GAAA,GACA,GAAA,OACI,GAAA,QACC,GAAA,IACJ,GAAA,MACE;AAAA,SAAA,OAGA,KAAK,GAAM,IAAI,SAAA,IAAA;AAAA,MAChB,MAAO,EAAK;MAGX,UAAU,QAAQ;;AAG1B,mBAA0B,IAAG,GAAG,GAAA;AAAA,MAAM,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAK,QAAQ,IAAA,UAAA;AAAA,MAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA,KAC/B,eAAe,GAAO,mBAAmB;AAAA,MAExD,IAAA,EAAA,WACQ,cAAA,GACR,GAAA,GACA,GAAA,OACI,GAAA,QACC,OAAA,MACF,KAEH,IAAO,UAAU,QAAA,EAAA,WACT,uBAAA,GACR,GAAA,GACA,GAAA,IACc,IAAZ,YAAiB,MAAA,aACI,MAAZ,YAAmB,MAAA,eAClB,SAAA,MACT,WAAA,WACK,MAGR,IAAQ,UAAU,KAAA,EAAA,WAAA,eACG,KAAA,OAAM,IAAA;AAAA,SAAA,EAEzB,YAAY,UAAU,QAAQ,KAAA,EAC9B,YAAY,IAEX;;AAGR,mBAA0B,IAAG,GAAG,GAAA;AAAA,MAAM,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAK,QAAQ,IAAA,UAAA;AAAA,MAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA,KAC/B,eAAe,GAAO,mBAAmB;AAAA,MAExD,IAAA,EAAA,WACQ,cAAA,IACP,GAAA,IACA,GAAA,GACD,GAAA,MACG,KAEH,IAAO,UAAU,QAAA,EAAA,WACT,uBAAA,GACR,GAAA,GACA,GAAA,IACE,YAAa,MAAA,IACb,YAAU,IAAK,MAAA,aACM,MAAZ,YAAmB,MAAA,eAClB,SAAA,MACT,WAAA,WACK,MAGR,IAAQ,UAAU,KAAA,EAAA,WAAA,eACG,KAAA,OAAM,IAAA;AAAA,SAAA,EAEzB,YAAY,UAAU,UAAU,KAAA,EAChC,YAAY,IAEX;;AAGR,kBAAyB,IAAW,GAAG,GAAG,GAAA;AAAA,MAAS,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAC9C,IAAW,EAAQ,YAAY;AAAA,SAI5B,UAAU,QAAA,EAAA,WACL,IAAA,GACR,GAAA,GACA,GAAA,IAAA,CANK,EAAQ,OAMb,SANgC,EAAQ,KAAM,IAAW,KAOnD,MAAA,aACI,IAAW,MAAA,MAPd,EAAQ,QAAQ,WAAA,eACV,EAAQ,cAAc,SAAA,WAS3B;;AAIb,sBAAsB,IAAG,GAAO,GAAI,GAAA;AAAA,MAAI,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA;AACnC,IAAQ,UAAQ,GAAQ,SAAS;AAAA,MACjC,IAAI,UAAU,QAAA,EAAA,WACN,mBAAmB,EAAQ,WAAA,IAClC,GAAA,IACA,GAAA,IACA,GAAA,IACA,GAAA,QAAA,EAAA,QAEK,EAAQ,aAId,IAAO,UAAU,QAAA,EAAA,GACjB,GAAA,GACA,IAAK,IAAK,IAAK,eAAe,IAAK,eAAe,WAAA,IACjD,YAAY,MAAA,aACH,YAAY,MAAA,eACV,UAAA,WACJ,IAAQ,OAGhB,IAAO,UAAU,KAAA,EAAA,WAAA,eACK,KAAA;AAAA,SAAA,EAGrB,YAAY,IAAA,EACZ,YAAY,IAEV;;AAGR,sBAAsB,IAAG,GAAO,GAAI,GAAA;AAAA,MAAI,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA;AACnC,IAAQ,UAAQ,GAAQ,SAAS,kBACjC,EAAQ,YAAU,GAAQ,WAAW,KACrC,EAAQ,kBAAgB,KAAQ,mBAAmB;AAAA,MAKnD,IAAI,UAAU,QAAA,EAAA,WAHF,qBAAqB,EAAQ,YACtB,CAArB,EAAQ,aAAa,WAAW,WAAU,KAAA,IAIvC,GAAA,IACA,GAAA,IACA,GAAA,IACA,GAAA,QAAA,EAAA,QAEK,EAAQ,aAId,IAAO,UAAU,QAAA,EAAA,GACjB,IAAK,IAAK,IAAK,eAAe,IAAK,cAAA,GACnC,GAAA,IACE,YAAY,IAAI,IAAK,MAAA,aACb,YAAY,MAAA,eACV,IAAK,IAAK,QAAQ,SAAA,WACtB,IAAM,OAGd,IAAO,UAAU,KAAA,EAAA,WAAA,kBACO,KAAA,KAAA,kBACT;AAAA,SAGP,AAAT,MAAS,KAAc,AAAT,MAAS,OAAT,GACX,MAAM,SAAS,0BAAA,EAGhB,YAAY,IAAA,EACZ,YAAY,IAEV;;AAGR,eAAsB,IAAG,GAAO,GAAA;AAAA,MAAO,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA;AACjC,gBAAc,OAAI,MAAI,IAEvB,EAAQ,OAAK,GAAQ,MAAM,SAC3B,EAAQ,UAAQ,GAAQ,SAAS,IACjC,EAAQ,QAAM,GAAQ,OAAO,SAC7B,EAAQ,UAAQ,GAAQ,SAAS,kBACjC,EAAQ,aAAW,GAAQ,YAAY;AAAA,MAEvC,IAAA,KAAU,kBACV,IAAsB,AAAjB,EAAQ,SAAS,SAAS,IAAQ,mBAAmB;AAAA,SAE1C,AAAjB,EAAQ,SAAS,UAA0B,AAAhB,EAAQ,QAAQ,WAAR,KAChC,IAAQ,kBAAA,IACR,IAAA,KAKA,EAAQ,QAAA,KACR,EAAQ,QAEP,aAAa,IAAG,GAAO,GAAI,GAAA,EAAA,QACzB,EAAQ,QAAA,WACL,EAAQ,WAAA,UACT,EAAQ,UAAA,gBACF,EAAQ;;AAI1B,eAAsB,IAAG,GAAO,GAAA;AAAA,MAAQ,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA;AAClC,gBAAc,OAAI,MAAI,IAEvB,EAAQ,OAAK,GAAQ,MAAM,WAC3B,EAAQ,UAAQ,GAAQ,SAAS,IACjC,EAAQ,QAAM,GAAQ,OAAO,SAC7B,EAAQ,UAAQ,GAAQ,SAAS,kBACjC,EAAQ,aAAW,GAAQ,YAAY;AAAA,MAavC,IAAK,IAAS,kBACd,IAAsB,AAAjB,EAAQ,SAAS,SAAT,KAAuB,mBAAmB;AAAA,SAEvC,AAAjB,EAAQ,SAAS,UAA0B,AAAhB,EAAQ,QAAQ,SAAR,KAAA,KAE3B,kBAAA,IACL,IAGC,aAAa,IAAG,GAAO,GAAI,GAAA,EAAA,QACzB,EAAQ,QAAA,WACL,EAAQ,WAAA,UACT,EAAQ;;AAIpB,iBAAwB,IAAG,GAAO,GAAA;AAAA,MAAO,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA;AACpC,IAAQ,YAAU,GAAQ,WAAW;AAAA,MAIrC,IAAW,UAAU,QAAA,EAAA,WACb,eAAA,GAJiB,AAArB,EAAQ,aAAa,SAAS,eACnC,IAAQ,eAAe,GAAO,KAAK,cAAA,GAKlC,GAAA,IACE,YAAA,KAAkB,MAAA,aACV,YAAY,MAAA,eACV,SAAA,WACJ,IAAM,OAGd,IAAO,aAAa,IAAG,IAAI,GAAG,GAAA,EAAA,QACzB,EAAQ,UAAU,iBAAA,WACf,EAAQ,aAAa,IAAA,UACtB,EAAQ;AAAA,SAAA,EAGd,YAAY,IAEV;;AAGR,iBAAwB,IAAI,GAAI,GAAO,GAAA;AAAA,MAAO,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAEzC,IAAS,KAAK,GAEd,IAAO,UAAU,QAAA,EAAA,WAAA,YAAA,QAAA,EAAA,MAAA,6BAAA,QAIX,iBAAA,oBACe,IAAA,OAAU,KAAA,GAG/B,GAAA,GACA,GAAA,OACI,GAAA,QACC;AAGL,IAAQ,YAAU,GAAQ,WAAW;AAAA,MAIrC,IAAW,UAAU,QAAA,EAAA,WACb,eAAA,GAJiB,AAArB,EAAQ,aAAa,SAAS,eACnC,IAAQ,eAAe,IAAM,IAAI,OAAO,cAAA,GAKvC,GAAA,IACE,YAAA,KAAkB,MAAA,aACV,YAAY,MAAA,eACV,SAAA,WACJ,IAAM,OAGd,IAAS,UAAU,KAAA,EAAA,WAAA,kBACK,IAAA;AAAA,SAAA,EAGrB,YAAY,IAAA,EACZ,YAAY,IAEZ;;AAGR,oBAA2B,IAAG,GAAM,GAAO,GAAA;AAAA,MAAO,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAM,IAAI,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAM,GAAG,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAO,GAAG,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAAA,IAC5D,qBAAqB,GAAM,EAAK,WAAA,IAAA,eAAA,GAAA,IAA7C,IAAA,EAAA,IAAQ,IAAA,EAAA;AAAA,OACR,GAES,AAAX,MAAW,KAAX,KACO,EAAK,WAAA,KACT,EAAK,YAIN,cAAc,OAAI,MAAI,IACtB,cAAc,MAAI,KAAI,IACtB,cAAc,GAAA,SAAe,KAAS,IACtC,cAAc,GAAA,SAAc,KAAQ;AAAA,MAErC,IAAO,UAAU,QAAA,EAAA,WAAA,YAAA,OAAA,WAEJ,GAAA,oBACI,GAAA,GACjB,IAAA,GACA,GAAA,OACI,GAAA,QACC;AAAA,MAAA,MAGA,OAEK,EAAM,QAEb;AAAA,MACD,aAAa,KAAK,IAAA,EAClB,aAAa,KAAK;AAAA,QACnB,IAAO,UAAU,QAAA,EAAA,WACT,oBAAA,GACR,IAAM,GAAA,GACN,GAAA,IACE,YAAY,IAAA,KAAU,MAAA,aACd,YAAY,MAAA,eACV,UAAA,WACJ,MAGR,IAAQ,UAAU,KAAA,EAAA,oBACD,GAAA,WAAA,eACI,KAAA,OAAM,IAAA;AAAA,WAAA,EAEzB,YAAY,IAAA,EACZ,YAAY,IAEX;;AAAA,SArBA;;AAyBT,oBAA2B,IAAG,GAAG,GAAQ,GAAA;AAAA,MAAO,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAM,IAAI,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAM,GAC3D,IAAM,UAAU,UAAA,EAAA,OAAA,WACH,GAAA,oBACI,GAAA,IAChB,IAAA,IACA,GAAA,GACD;AAAA,MAAA,MAGK,OAEK,EAAM,QAEb;AAAA,MACF,aAAa,MAAM,IAAA,EACnB,aAAa,MAAM;AAAA,QAEnB,IAAO,UAAU,QAAA,EAAA,WACT,oBAAA,GACR,GAAA,GACA,GAAA,IACE,YAAY,IAAA,KAAS,IAAU,MAAA,aACvB,YAAY,MAAA,eACV,UAAA,WACJ,MAGR,IAAQ,UAAU,KAAA,EAAA,oBACD,GAAA,WAAA,eACI,KAAA,OAAM,IAAA;AAAA,WAAA,EAEzB,YAAY,IAAA,EACZ,YAAY,IAEX;;AAAA,SAtBA;;AA0BT,kBAAyB,IAAO,GAAO,GAAA;AAAA,MAAO,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAAY,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAErD,IADa,EAAM,IAAI,SAAC,IAAG,IAAA;AAAA,WAAO,GAAM,MAAK,MAAM;KAC5B,KAAK;AAG5B,IAAQ,UACX,KAAY,wBAAwB,IAAO;AAAA,MAExC,IAAO,SAAS,MAAI,GAAW,mBAAmB;AAAA,MAGnD,EAAQ,UAAU;AAAA,QAChB,IAAc,aAAa,EAAK,SAAS;AAAA,MACxC,MAAM,SAAA,UAAiB,IAAA;;AAAA,MAGzB,IAAA,EAAA,MACG;AAAA,MAIJ,EAAQ,YAAY;AAAA,QAClB,IAAqB,aAAa,EAAK,SAAS,GAAA,OAEhD,IAAU,MAAS,GAAM,KAAA,MAAM,EAAK,WAAA,MAAc,IAAA,MAAgB,GAAM,MAAA,IAAU,KAAA,MAAM,EAAK;AAAA,MAC3F,SAAS,SAAS,GAAA,eAAwB,QAAA,UAAgB,IAAA;;AAAA,SAG1D;;AChmBR,mBAA0B,IAAM,GAAU,GAAU,GAAA;AAAA,MAC/C,IAA0B,AAAA,OAAb,KAAa,WAAW,IAAW,EAAS,KAAK;AAAA,SAAA,CAEjE,IAAA,EACC,WAAW,EAAS,KAAK,SAC1B,GACA,YACA,aAAA,EACC,WAAW;;AAId,2BAAkC,IAAO,GAAM,GAAA;AAAA,SACvC,UAAU,IAAA,CAAQ,GAAM,IAAA,CAAK,GAAM,IAAI;;AAG/C,2BAAkC,IAAO,GAAM,GAAA;AAAA,SACvC,UAAU,IAAA,CAAQ,GAAG,IAAA,CAAQ,GAAG,IAAO;;AAG/C,uBAA8B,IAAW,GAAO,GAAO,GAAA;AAAA,MAClD,IAAY,IAAQ,GACpB,IAAO,GAAU,WAAW;AAAA,SAAA,CAAA,CAG/B,GAAA,EACE,QAAQ,GAAW,oBAHV,EAAK,aAAa,WAAA,OAGyB,KACtD,sBACA,aAGe,UAAU,IAAA,CAAY,GAAG,IAAA,CAAS,GAAG,IAAQ;;AAI9D,oBAA2B,IAAK,GAAG,GAAM,GAAA;AAAA,MAAO,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAO,GAAA,IACpC,qBAAqB,GAAA,WAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAAW,WAAA,IAAA,iBAAA,GAAA,IAA7C,IAAA,EAAA,IAAQ,IAAA,EAAA;AAAA,SAAA,KACR,GACe,AAAjB,GAAI,aAAa,SAAb,CAAA,CACK,GAAI,WAAW,IAAA,EAGxB,OAAO,GAAO,QAAQ,KACvB,eACA,aAIe,UAAU,IADR,GAAI,aAAa,aAAa,MAAM,KAAK,GAAG,MAAM,GAAA,KAAI,CAC3B,GAAG,IAAI,yBAAA,CAAA,CAG3C,IAAA,EAAM,OAAO,GAAO,QAAQ,GAAQ,GAAG,GAAG,GAAG,KAAI,eAAe;;AAK3E,oBAA2B,IAAK,GAAG,GAAA;AAAA,SACd,AAAjB,GAAI,aAAa,WAAb,CAEU,UAAU,IADR,GAAI,aAAa,aAAa,MAAM,KAAK,GAAG,MAAM,GAAA,KAAI,CAC3B,GAAG,IAAI,yBAAA,CAAA,CAG3C,IAAA,EAAM,IAAI,GAAG,IAAI,KAAI,eAAe;;AAK/C,qBAA4B,IAAO,GAAU,GAAU,GAAU,GAAA;AAAA,MAC5D,IAAA,IACA,IAAY,EAAS,IAAI,SAAC,IAAG,IAAA;AAAA,WAAO,EAAS,MAAK,MAAM;KAAI,KAAK;AAEjE,OACH,KAAY,wBAAwB,GAAU;AAAA,MAEzC,IAAA,CAAY,GAAM,MAAA,EAAO,GAAE,MAAM,KAAY,eAAe;AAAA,MAAA,EACnD,KAAK,IAEjB,GAAM,QAAQ;AAAA,QACZ,IAAgB,EAAS,KAAA,MAAM,IAAA,KAC/B,IAAA,MAAe,EAAS,MAAA,IAAU,KAAA,OAAO,GAEvC,IAAA,CACL,GAAM,QAAA,EACL,GAAE,MAAM,IAAa,IAAY,KAClC,eACA;AAAA,MAEc,KAAK;;AAAA,SAGd;;AAGR,wBAA+B,IAAS,GAAA;AAAA,SAAA,CAC/B,IAAA,EAAU,GAAG,KAAU,eAAe;;AAAA,8BAAA,IAAA;AAAA,MAAA,MAAA,QAAA,KAAA;AAAA,aAAA,IAAA,GAAA,IAAA,MAAA,GAAA,SAAA,IAAA,GAAA,QAAA;AAAA,QAAA,KAAA,GAAA;AAAA,WAAA;;AAAA,SAAA,MAAA,KAAA;;AC1F/C,2BAA2B,IAAS,GAAO,GAAA;AAAA,MAAK,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAW,UAAU,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,QAAgB,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAEhF,IAAc,GAAQ,UAAA,OACtB,IAAa,GAAQ,UAAA;AAAU,WAE3B,KAAiB,GAAO;AAAA,QAC3B,IAAA;AAAA,QACiB,AAAlB,MAAkB,cACH,SAAS,gBAAgB,8BAA8B,sBAEvD,SAAS,gBAAgB,8BAA8B;AAAA,QAErE,IAAe,EAAU,MAAkB,GAAQ,aAAa,IAChE,IAAQ,EAAM,IAEd,IAAA,EAAA,eACY,GAAA,MACT,GAAA,IACF,GAAA,OACG,MAAA,KACF,IAAI,MAAO,KAAA,QACR,IAAe,MAAM,GAAA,YACjB,OAAO,IAAA,UACT,OAAA,UACA,UAAA,MACJ;AAGJ,SAAA,GACF,OAAmB;AAAA,aAGX,KAAK;AAAA,QACE,aAAa,GAAG,EAAS;AAAA,MAG7B,YAAY,IAErB,IAAA,EACS,aAAa,GAAA,eAA4B,IAAA,OAAA,EAEzC,aAAa,GAAe;;AAAA,SAAA,CAIjC,GAAa;;AAGtB,mBAA0B,IAAS,GAAA;AAAA,KAC1B,MAAM,YAAY,GAAA,GAClB,MAAM,kBAAkB,GAAA,GACxB,MAAM,cAAc,GAAA,GACpB,MAAM,eAAe,GAAA,GACrB,MAAM,aAAa;;AAG5B,oBAAoB,IAAc,GAAA;AAAA,MAC7B,IAAA,IACA,IAAA;AAAA,IAEK,IAAI,SAAA,IAAA;AAAA,QACR,KAAO,GAAQ,IACf,KAAS,GAAK,YAEd,IAAA,QAAa,IAAA;AAAA,OAET,KAAK;AAAA,QAAA,IACe,kBAAA,MAAA,QAAA,qBAAqB,MAAA,IAAA,iBAAA,GAAA;AAAA,QAAA,EAAA,IAAA,IAAA,EAAA,IAAA,EAErC,KAAK,IAAA,EACJ,KAAA,CAAM,GAAa,MAE5B,MAAA,GACI,aAAa,GAAa;;AAAA,MAI/B,IAAU,GAAa,UAAA;AAAU,SAAA,EAExB,IAAI,SAAC,IAAa,IAAA;AAC1B,OAAY,MAAA,IACH,GAAG,aAAa,EAAY,KAAI,GAAY,KAAA,EAC/C,IAAG,KAAK,EAAY;MAIxB;;AAGR,0BAAiC,IAAQ,GAAY,GAAA;AAAA,MACpB,AAA7B,EAAkB,WAAW,GAAX;AAAA,QAEjB,IAAiB,WAAW,GAAY;AACzC,MAAW,cAAc,MAAA,IACpB,YAAY,IAAA,GACZ,YAAY,KAAA,WAKT,WAAA;AACP,QAAe,cAAc,MAAA,IACxB,YAAY,IAAA,GACZ,YAAY;OAElB;;;ACnHG,sBAAsB,IAAU,GAAA;AAAA,MAClC,IAAI,SAAS,cAAc;AAAA,IAC7B,QAAQ;AAAA,MACN,IAAO,IAAI,KAAK,GAAA,EAAO,MAAM,mCAC7B,IAAM,OAAO,IAAI,gBAAgB;AAAA,IACnC,OAAO,GAAA,EACP,WAAW,IAAA,SACJ,KAAK,YAAY,IAAA,EACxB,SAAA,WACS,WAAA;AAAA,aACD,KAAK,YAAY,IAAA,OACnB,IAAI,gBAAgB;KACzB;;AAGJ,0BAAiC,IAAA;AAAA,MAC5B,IAAQ,GAAI,UAAA;AAAU,IACpB,UAAU,IAAI,oBAAA,EACd,aAAa,SAAS,+BAAA,EACtB,aAAa,eAAe;AAAA,MAC9B,IAAU,EAAE,OAAO,SAAA,EAAA,WACT;AAAA,IAER,aAAa,GAAS,EAAM;AAAA,MAE9B,IAAY,EAAE,OAAO;AAAA,SAAA,EACf,YAAY,IAEf,EAAU;;AAAA,2BAAA,IAAA,GAAA;AAAA,MAAA,CAAA,eAAA;AAAA,UAAA,IAAA,UAAA;;AAAA,2BAAA,IAAA,GAAA;AAAA,MAAA,CAAA,eAAA;AAAA,UAAA,IAAA,UAAA;;AAAA,sCAAA,IAAA,GAAA;AAAA,MAAA,CAAA;AAAA,UAAA,IAAA,eAAA;AAAA,SAAA,CAAA,KAAA,AAAA,OAAA,KAAA,YAAA,AAAA,OAAA,KAAA,aAAA,KAAA;;AAAA,qBAAA,IAAA,GAAA;AAAA,MAAA,AAAA,OAAA,KAAA,cAAA,AAAA,MAAA;AAAA,UAAA,IAAA,UAAA,6DAAA,OAAA;AAAA,KAAA,YAAA,OAAA,OAAA,KAAA,EAAA,WAAA,EAAA,aAAA,EAAA,OAAA,IAAA,YAAA,OAAA,UAAA,MAAA,cAAA,WAAA,KAAA,QAAA,iBAAA,OAAA,eAAA,IAAA,KAAA,GAAA,YAAA;;ACblB,oBAAoB,IAAA;AAAA,MACf,IAAS,IAAI,KAAK;AAAA,SAAA,EACf,WAAW,EAAO,eAAe,EAAO,sBACxC;;AAGR,qBAA4B,IAAA;AAAA,MACvB,IAAK,GAAK,WACV,IAAK,GAAK,aAAa;AAAA,SAAA,CAE1B,GAAK,eACJ,KAAG,IAAI,KAAK,OAAO,GACnB,KAAG,IAAI,KAAK,OAAO,GACnB,KAAK;;AAGR,eAAsB,IAAA;AAAA,SACd,IAAI,KAAK,GAAK;;AAiBtB,yBAAgC,IAAW,GAAA;AAAA,MACtC,IAAgB,eAAe;AAAA,SAC5B,KAAK,KAAK,eAAe,GAAe,KAAW;;AAG3D,wBAA+B,IAAW,GAAA;AAAA,MACrC,IAAqB,aAAa;AAAA,SAC9B,YAAW,KAAW,WAAW,OAAc;;AAGxD,wBAA+B,IAAW,GAAA;AAAA,SAClC,GAAU,eAAe,EAAQ,cACpC,GAAU,kBAAkB,EAAQ;;AAGzC,sBAA6B,IAAA;AAAA,MAAG,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA,IAC3B,IAAY,YAAY;AAAA,SACrB,IAAQ,EAAU,MAAM,GAAG,KAAK;;AAGxC,4BAAoC,IAAO,GAAA;AAAA,SACnC,IAAI,KAAK,GAAM,KAAQ,GAAG;;AAIlC,wBAA+B,IAAA;AAAA,MAC1B,IAAU,MAAM,KACd,IAAM,EAAQ;AAAA,SACT,AAAR,MAAQ,KAAR,QACM,GAAA,KAAgB,IAElB;;AAIR,iBAAwB,IAAM,GAAA;AAAA,KACxB,QAAQ,GAAK,YAAY;;AAAA,2BAAA,IAAA,GAAA;AAAA,MAAA,CAAA,eAAA;AAAA,UAAA,IAAA,UAAA;;AC6V/B,sBAA6B,IAAM,GAAW,GAAA;AAAA,MACzC,IAAO,OAAO,KAAK,kBAAkB,OAAO,SAAA,IAAA;AAAA,WAAK,GAAK,SAAS;MAC/D,IAAS,iBAAiB,EAAK;AAAA,SAAA,OAC5B,OAAO,GAAA,EAAA,WACF,GAAA,SACF,MAEH,IAAI,eAAe;;AAAA,4BAAA,IAAA;AAAA,MAAA,MAAA,QAAA,KAAA;AAAA,aAAA,IAAA,GAAA,IAAA,MAAA,GAAA,SAAA,IAAA,GAAA,QAAA;AAAA,QAAA,KAAA,GAAA;AAAA,WAAA;;AAAA,SAAA,MAAA,KAAA;;AAAA,2BAAA,IAAA,GAAA;AAAA,MAAA,CAAA,eAAA;AAAA,UAAA,IAAA,UAAA;;AAAA,oCAAA,IAAA,GAAA;AAAA,MAAA,CAAA;AAAA,UAAA,IAAA,eAAA;AAAA,SAAA,CAAA,KAAA,AAAA,OAAA,KAAA,YAAA,AAAA,OAAA,KAAA,aAAA,KAAA;;AAAA,mBAAA,IAAA,GAAA;AAAA,MAAA,AAAA,OAAA,KAAA,cAAA,AAAA,MAAA;AAAA,UAAA,IAAA,UAAA,6DAAA,OAAA;AAAA,KAAA,YAAA,OAAA,OAAA,KAAA,EAAA,WAAA,EAAA,aAAA,EAAA,OAAA,IAAA,YAAA,OAAA,UAAA,MAAA,cAAA,WAAA,KAAA,QAAA,iBAAA,OAAA,eAAA,IAAA,KAAA,GAAA,YAAA;;AAAA,8BAAA,IAAA;AAAA,MAAA,MAAA,QAAA,KAAA;AAAA,aAAA,IAAA,GAAA,IAAA,MAAA,GAAA,SAAA,IAAA,GAAA,QAAA;AAAA,QAAA,KAAA,GAAA;AAAA,WAAA;;AAAA,SAAA,MAAA,KAAA;;AAAA,2BAAA,IAAA,GAAA;AAAA,MAAA,CAAA,eAAA;AAAA,UAAA,IAAA,UAAA;;AAAA,sCAAA,IAAA,GAAA;AAAA,MAAA,CAAA;AAAA,UAAA,IAAA,eAAA;AAAA,SAAA,CAAA,KAAA,AAAA,OAAA,KAAA,YAAA,AAAA,OAAA,KAAA,aAAA,KAAA;;AAAA,qBAAA,IAAA,GAAA;AAAA,MAAA,AAAA,OAAA,KAAA,cAAA,AAAA,MAAA;AAAA,UAAA,IAAA,UAAA,6DAAA,OAAA;AAAA,KAAA,YAAA,OAAA,OAAA,KAAA,EAAA,WAAA,EAAA,aAAA,EAAA,OAAA,IAAA,YAAA,OAAA,UAAA,MAAA,cAAA,WAAA,KAAA,QAAA,iBAAA,OAAA,eAAA,IAAA,KAAA,GAAA,YAAA;;AAAA,8BAAA,IAAA;AAAA,MAAA,MAAA,QAAA,KAAA;AAAA,aAAA,IAAA,GAAA,IAAA,MAAA,GAAA,SAAA,IAAA,GAAA,QAAA;AAAA,QAAA,KAAA,GAAA;AAAA,WAAA;;AAAA,SAAA,MAAA,KAAA;;AC5b3B,mBAEmB,IAAA;AAAA,MAKX,AAAJ,OAAI;AAAJ,WAAA,CACM,GAAG;AAAA,MAET,MAAM;AAAA,WAAA,EACA,UAAA,mBAA6B,UAAU;AAAA,MAE5C,IAAM,KAAI,IAAI,IAAA;AAAK,MAAA,CACnB,SAAS;AAAA,WAAA,EACJ,UAAgB,mBAAN,GAAwB,UAAU;AAAA,OAGjD,KAAK,IAAI;AAAA,MACT,IAAM,KAAK,MAAM,KAAK,MAAM;AAAA,SAAA,CAGxB,IAFE,MAAE,KAAK,IAAI,IAAI,KAEN;;AAGpB,gCAAgC,IAAA;AAAA,MAAK,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAI,GACpC,IAAa,KAAK,KAAK,KACvB,IAAa,KAAK,MAAM,IACxB,IAAQ,IAAa,GAErB,IAAY,GACZ,IAAW;AAGZ,MAAQ,KACP,KAAQ,KAAM,KAAA,KAAA,EAAA,IAGK,IAAA,IAEV,IAAM,GAAA,IACP,IAIT,KAAS,KAAA,KAEA,IAAA,KADC,KAKA,AAAV,MAAU,KAAV,KACU,GAAA,IACD;AAAA,WAGR,IAAA,IACI,IAAI,GAAG,KAAK,GAAW;AAAA,MACpB,KAAK,IAAa,IAAW;AAAA,SAEjC;;AAGR,2BAA2B,IAAA;AAAA,MAAU,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAS,GAAA,IACZ,UAAU,KAAA,IAAA,iBAAA,GAAA,IAAtC,IAAA,EAAA,IAAgB,IAAA,EAAA,IACjB,IAAiB,IAAW,IAAS,KAAK,IAAI,IAAI,KAAW,GAK7D,IAAY,uBAAA,IAFC,EAAe,QAAQ,IAEe;AAAA,SAAA,IAC3C,EAAU,IAAI,SAAA,IAAA;AAAA,WAAS,KAAQ,KAAK,IAAI,IAAI;;;AAIzD,4BAAmC,IAAA;AAAA,aAYC,IAAU,IAAA;AAAA,aACxC,KAAY,kBAAkB,KAE9B,KAAe,GAAU,KAAK,GAAU,IAGxC,KAAQ,GACJ,KAAI,GAAG,KAAQ,IAAa;AAAA,YAC1B,IAAA,GACC,QAAA,KAAe;AAAA,WAEnB;;AAAA,MAvBkC,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA,IAMtC,IAAW,KAAK,IAAA,MAAA,MAAA,qBAAO,MACvB,IAAW,KAAK,IAAA,MAAA,MAAA,qBAAO,MAGT,IAAA;AAAA,MAkBf,KAAY,KAAK,KAAY;AACpB,cAAU,GAAU,IAAA,IAC3B,IAGS,kBAAkB,GAAU,KAF5B,kBAAkB;WAQxB,IAAW,KAAK,IAAW,GAAG;AAAA,QAOjC,IAAc,KAAK,IAAI;AAExB,SAAY,IACH,WAAU,GAAU,IAAA,IACnB,EAA0B,GAAU,MAGrC,WAAU,GAAa,IAAA,IACf,EAA0B,GAAa,GACjC,UAAU,IAAI,SAAA,IAAA;AAAA,aAAA,KAAK;;aAOtC,KAAY,KAAK,KAAY,GAAG;AAAA,QAInC,IAAiB,KAAK,IAAI,IAC1B,IAAiB,KAAK,IAAI;AAEnB,cAAU,GAAgB,IAAA,IAAA,KACjC,IAGS,kBAAkB,GAAgB,KAFlC,kBAAkB,IAKT,UAAU,IAAI,SAAA,IAAA;AAAA,aAAA,KAAK;;;AAAA,SAGnC;;AAGR,sBAA6B,IAAA;AAAA,MAExB,IAAW,gBAAgB;AAAA,SAC5B,GAAK,QAAQ,MAAM,IAGT,GAAK,QAAQ,KAChB,GAAK,KAAK,IAAA,KAGT,GAAK,KACU,IAAA,KAIf,GAAK,GAAK,SAAS,KACJ,IAAY,IAAK,SAAS;;AAiBrD,yBAAgC,IAAA;AAAA,SACxB,GAAa,KAAK,GAAa;;AAGvC,uBAA8B,IAAA;AAAA,SACtB,GAAa,GAAa,SAAO,KAAK,GAAa;;AAG3D,eAAsB,IAAK,GAAA;AAAA,SACnB,SAAS,EAAM,WAAW,KAAM,EAAM;;AAY9C,2BAAkC,IAAM,GAAA;AAAA,MAAK,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA,IACxC,IAAU,EAAI,OAAO,SAAS,IAAM,IAAA;AAAA,WAC/B,KAAK,IAAI,KAAO,MAAQ,KAAK,IAAI,KAAO,MAAQ,KAAO;KAAA;AAAA,SAGzD,IAAQ,EAAI,QAAQ,KAAW;;AAGvC,0BAAiC,IAAQ,GAAA;AAAA,WAIpC,IAAe,KAAK,IAAA,MAAA,MAAA,qBAAO,MAE3B,IAAmB,IAAK,KAAmB,IAC3C,IAAA,IAEI,IAAI,GAAG,IAAI,GAAkB,KAAK;AAAA,QACrC,IAAa,IAAgB,KAAmB;AAAA,MACvC,KAAK;;AAAA,SAGZ;;AAGR,0BAAiC,IAAO,GAAA;AAAA,SAChC,EAAa,OAAO,SAAA,IAAA;AAAA,WAAK,KAAI;KAAO;;AAAA,8BAAA,IAAA;AAAA,MAAA,MAAA,QAAA,KAAA;AAAA,aAAA,IAAA,GAAA,IAAA,MAAA,GAAA,SAAA,IAAA,GAAA,QAAA;AAAA,QAAA,KAAA,GAAA;AAAA,WAAA;;AAAA,SAAA,MAAA,KAAA;;AAAA,2BAAA,IAAA,GAAA;AAAA,MAAA,CAAA,eAAA;AAAA,UAAA,IAAA,UAAA;;AAAA,sCAAA,IAAA,GAAA;AAAA,MAAA,CAAA;AAAA,UAAA,IAAA,eAAA;AAAA,SAAA,CAAA,KAAA,AAAA,OAAA,KAAA,YAAA,AAAA,OAAA,KAAA,aAAA,KAAA;;AAAA,qBAAA,IAAA,GAAA;AAAA,MAAA,AAAA,OAAA,KAAA,cAAA,AAAA,MAAA;AAAA,UAAA,IAAA,UAAA,6DAAA,OAAA;AAAA,KAAA,YAAA,OAAA,OAAA,KAAA,EAAA,WAAA,EAAA,aAAA,EAAA,OAAA,IAAA,YAAA,OAAA,UAAA,MAAA,cAAA,WAAA,KAAA,QAAA,iBAAA,OAAA,eAAA,IAAA,KAAA,GAAA,YAAA;;AAAA,8BAAA,IAAA;AAAA,MAAA,MAAA,QAAA,KAAA;AAAA,aAAA,IAAA,GAAA,IAAA,MAAA,GAAA,SAAA,IAAA,GAAA,QAAA;AAAA,QAAA,KAAA,GAAA;AAAA,WAAA;;AAAA,SAAA,MAAA,KAAA;;AC7O5C,kBAGyB,IAAM,GAAA;AAAA,KACzB,SAAS,GAAK,UAAA;AAAA,MAEf,IAAgB,GAAK,OAAO,QAG5B,IAAW,GAAK,UAChB,IAAY,IAAI,MAAM,GAAe,KAAK;AAAA,SAC1C,KAAA,KAAA,CAAA,EAAA,QAGM,OAAA,EAID,IAAI,SAAA,IAAA;AAAA,QAER,GAAE,QAEC;AAAA,UAEF,KAAO,GAAE;AAAA,WAAA,MACN,GAAK,IAAI,SAAA,IAAA;AAAA,eAAS,MAAM,MAAa,IAAN;UAG9B,SAAS,IACT,GAAK,MAAM,GAAG,KAEd,UAAU,IAAM,IAAgB,GAAK,QAAQ,IAAA,GAEnD,SAAS;;AAAA,SAZT,SAAS;AAgBR,OAAE,aACD,0BAAyB,SAAS,IAAA,GACpC,YAAY;MASb,GAAK,YAAA,GACF,SAAS,IAAI,SAAA,IAAA;AAAA,QACd,GAAE,MAAM,GAAE,OAAO;AAAA,UAAA,KAAA,CACC,GAAE,KAAK,GAAE;AAAA,SAA1B,QAAA,GAAA,IAAA,GAAS,MAAA,GAAA;;MAKR;;AAGR,sBAA6B,IAAA;AAAA,MACxB,IAAgB,GAAS,OAAO,QAChC,IAAY,IAAI,MAAM,GAAe,KAAK,IAE1C,IAAA,EAAA,QACK,GAAS,OAAO,MAAM,GAAA,KAAI,UACxB,GAAS,SAAS,IAAI,SAAA,IAAA;AAAA,WAAA,EAAA,MAExB,IAAA,QACE,EAAU,MAAM,GAAA,KAAI,WACjB,GAAE;;AAAA,SAKb,GAAS,YAAA,GACF,WAAA,CAAA,EAAA,OAEA,GAAA,OACA,QAKP,GAAS,YAAA,GACF,WAAA,CAAA,EAAA,OAEA,GAAA,KACF,GAAA,OACE,QAKH;;AAGR,4BAAmC,IAAA;AAAA,MAAY,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAAW,IAAA,CAAA,WAAA,SAAA,KAAA,AAAA,UAAA,OAAA,WAAA,UAAA,IACrD,IAAe,KAAa,EAAO;AACpC,OAAgB,KAAG,KAAe;AAAA,MACjC,IAAiB,IAAe,oBAEhC,IAAA;AAAA,MACD,GAAU;AAAA,QAER,IAAiB,KAAK,IAAA,MAAA,MAAA,qBAAO,EAAO,IAAI,SAAA,IAAA;AAAA,aAAS,GAAM;;AAAA,QAC1C,KAAK,KAAK,IAAe;;AAAA,SAG1B,EAAO,IAAI,SAAC,IAAO,IAAA;AAAA,WAAA,OAC1B,IACA,SAAS,KAEb,KAOA,KAAI,KAAmB,KAAA,MACjB,MAAA,KAPN,IAAe,IAAI,IACb,GAAM,MAAM,GAAG,IAAe,KAAK,SAEnC,GAAM,MAAM,GAAG,KAAkB,OAQrC;;;AAAA,8BAAA,IAAA;AAAA,MAAA,MAAA,QAAA,KAAA;AAAA,aAAA,IAAA,GAAA,IAAA,MAAA,GAAA,SAAA,IAAA,GAAA,QAAA;AAAA,QAAA,KAAA,GAAA;AAAA,WAAA;;AAAA,SAAA,MAAA,KAAA;;AAAA,2BAAA,IAAA,GAAA;AAAA,MAAA,CAAA,eAAA;AAAA,UAAA,IAAA,UAAA;;AAAA,sCAAA,IAAA,GAAA;AAAA,MAAA,CAAA;AAAA,UAAA,IAAA,eAAA;AAAA,SAAA,CAAA,KAAA,AAAA,OAAA,KAAA,YAAA,AAAA,OAAA,KAAA,aAAA,KAAA;;AAAA,qBAAA,IAAA,GAAA;AAAA,MAAA,AAAA,OAAA,KAAA,cAAA,AAAA,MAAA;AAAA,UAAA,IAAA,UAAA,6DAAA,OAAA;AAAA,KAAA,YAAA,OAAA,OAAA,KAAA,EAAA,WAAA,EAAA,aAAA,EAAA,OAAA,IAAA,YAAA,OAAA,UAAA,MAAA,cAAA,WAAA,KAAA,QAAA,iBAAA,OAAA,eAAA,IAAA,KAAA,GAAA,YAAA;;AAAA,8BAAA,IAAA;AAAA,MAAA,MAAA,QAAA,KAAA;AAAA,aAAA,IAAA,GAAA,IAAA,MAAA,GAAA,SAAA,IAAA,GAAA,QAAA;AAAA,QAAA,KAAA,GAAA;AAAA,WAAA;;AAAA,SAAA,MAAA,KAAA;;AAAA,2BAAA,IAAA,GAAA;AAAA,MAAA,CAAA,eAAA;AAAA,UAAA,IAAA,UAAA;;AAAA,sCAAA,IAAA,GAAA;AAAA,MAAA,CAAA;AAAA,UAAA,IAAA,eAAA;AAAA,SAAA,CAAA,KAAA,AAAA,OAAA,KAAA,YAAA,AAAA,OAAA,KAAA,aAAA,KAAA;;AAAA,qBAAA,IAAA,GAAA;AAAA,MAAA,AAAA,OAAA,KAAA,cAAA,AAAA,MAAA;AAAA,UAAA,IAAA,UAAA,6DAAA,OAAA;AAAA,KAAA,YAAA,OAAA,OAAA,KAAA,EAAA,WAAA,EAAA,aAAA,EAAA,OAAA,IAAA,YAAA,OAAA,UAAA,MAAA,cAAA,WAAA,KAAA,QAAA,iBAAA,OAAA,eAAA,IAAA,KAAA,GAAA,YAAA;;AAAA,yBAAA,IAAA,GAAA;AAAA,MAAA,CAAA,eAAA;AAAA,UAAA,IAAA,UAAA;;ACzGT,0BAAS;AAAA,MAAe,KAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAY,QAAQ,IAAA,UAAA,IAAQ,IAAA,UAAA;AAAA,SACjC,AAAd,OAAc,eAAd,GACK,OAAO,QACR,IAAI,UAAU,GAAQ,MAGzB,WAAW,MAKT,IAAI,WAAW,IAAW,GAAQ,KAAA,KAAA,QAJhC,MAAM,2BAA2B;;AAAA,IAAA,WAAA;AAAA,YAAA;AAAA,IAAA,UAAA,AAAA,OAAA,UAAA,cAAA,AAAA,OAAA,OAAA,YAAA,WAAA,SAAA,IAAA;AAAA,SAAA,OAAA;IAAA,SAAA,IAAA;AAAA,SAAA,MAAA,AAAA,OAAA,UAAA,cAAA,GAAA,gBAAA,UAAA,OAAA,OAAA,YAAA,WAAA,OAAA;;AbZ3C,EAAE,SAAS,SAAC,IAAK,GAAA;AAAA,MACZ,IAAU,SAAS,cAAc;AAAA,WAE5B,KAAK,GAAG;AAAA,QACZ,IAAM,EAAE;AAAA,QAEF,AAAN,MAAM;AAAN,QACD,GAAK,YAAY;aAEL,AAAN,MAAM,UAAU;AAAA,UACpB,IAAM,EAAE;AAAA,QACR,WAAW,aAAa,GAAS,IAAA,EAC7B,YAAY;;AAEJ,MAAN,MAAM,WACE,AAAA,CAAR,MAAQ,SAAR,cAAA,QAAA,QAAQ,YAAR,OACF,KAAK,GAAK,IAAI,SAAA,IAAA;AAAA,UACZ,MAAM,MAAQ,EAAI;WAGlB,KAAK,IAAA,EACP,KAAK,IAAA,EAGL,aAAa,GAAG;;AAAA,SAInB;;ACxBD,IAAM,gBAAA,EAAA,SAAA,EAAA,KAEN,IAAA,QACG,IAAA,MACF,IAAA,OACC,MAAA,UAAA,EAAA,KAGF,IAAA,QACG,IAAA,MACF,IAAA,OACC,MAAA,YAGI,KAAA,aACC,IAAA,cACC,IAAA,eAEC;AAlBT,IA2CM,4BAA4B;AA3ClC,IA4CM,6BAA6B;AA5CnC,IA+CM,2BAAA,CAA4B,QAAQ;AA/C1C,IAiDM,uBAAuB;AAjD7B,IAmDM,wBAAwB;AAnD9B,IAoDM,yBAAyB;AApD/B,IAsDM,sBAAsB;AAtD5B,IAuDM,wBAAwB;AAvD9B,IAyDM,gCAAgC;AAzDtC,IA0DM,+BAA+B;AA1DrC,IA8DM,4BAA4B;AA9DlC,IAgEM,sBAAsB;AAhE5B,IAiEM,sBAAsB;AAjE5B,IAmEM,qBAAqB;AAnE3B,IAqEM,kCAAkC;AArExC,IAuED,uBAAA,CAAwB,cAAc,QAAQ,UAAU,OAAO,UACpE,UAAU,SAAS,eAAe,UAAU,WAAW,cAAc;AAxE/D,IAyED,uBAAA,CAAwB,WAAW,WAAW,WAAW,WAAW;AAzEnE,IA6EM,iBAAA,EAAA,KACP,sBAAA,MACC,sBAAA,KACD,sBAAA,YACO,sBAAA,SACH,sBAAA,OACF;AAnFD,IAuFM,cAAc,KAAK,KAAK;AAvF9B,IAwFM,aAAa;AAxFnB,IAwFmB,iBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,aAAA,IAAA,GAAA,IAAA,EAAA,QAAA,KAAA;AAAA,UAAA,IAAA,EAAA;AAAA,QAAA,aAAA,EAAA,cAAA,OAAA,EAAA,eAAA,MAAA,WAAA,KAAA,GAAA,WAAA,OAAA,OAAA,eAAA,IAAA,EAAA,KAAA;;;AAAA,SAAA,SAAA,GAAA,GAAA,GAAA;AAAA,WAAA,KAAA,GAAA,EAAA,WAAA,IAAA,KAAA,GAAA,GAAA,IAAA;;;AAxFnB,Iafc,SAAA,WAAA;AAAA,cAAA,GAAA;AAAA,QAAA,IAAA,EAEnB,QAAA,IAAA,AAAA,MAAA,SAAS,OAAA,GAAA,IAAA,EACT,QAAA,IAAA,AAAA,MAAA,SAAA,KAAA;AAAA,sBAAA,MAAA,KAAA,KAEK,SAAS,GAAA,KACT,SAAS,GAAA,KACT,YAAY,IAAA,KACZ,aAAa,IAAA,KACb,aAAA,IAAA,KACA,kBAAkB,GAAA,KAElB,IAAI,GAAA,KACJ,IAAI,GAAA,KAEJ,MAAM,GAAA,KACN,OAAO,GAAA,KAEP;;AAAA,SAAA,eAAA,IAAA,CAAA,EAAA,KAAA,SAAA,OAAA,WAAA;AAAA,SAIA;OAAA,EAAA,KAAA,WAAA,OAAA,WAAA;AAAA,SAIA,QAAA,KACA;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,SAIA,YAAY,EAAE,OAAO,OAAA,EAAA,QACjB,KAAK,QAAA,WACF,4BAAA,WAAA,8GAAA,KAKP,WAAA,KAEA,QAAQ,KAAK,UAAU,cAAc,WAAA,KACrC,gBAAgB,KAAK,UAAU,cAAc,qBAAA,KAE7C,OAAO,iBAAiB,cAAc,WAAA;AAAA,SACrC;;OAAA,EAAA,KAAA,QAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MAKF,IAAA;AACD,SAAK,SAAA,KACF,UAAU,aAAa,oBAAoB,KAAK,QAAA,IAEnD,KAAK,kBAAA,aACY,KAAK,aAAA,cAAsB,KAAK,YAExC,KAAK,YAAA,aAAoB,KAAK,aAAA,aAAA,KAErC,MAAM,YAAY,GAAA,KAClB,cAAc,YAAY,IAAA,KAE1B,WAAW,IAAI,SAAC,IAAK,GAAA;AAAA,UACnB,IAAQ,GAAK,OAAO,MAAM,SAC5B,IAA0B,AAAlB,GAAI,cAAc,KAAK,GAAI,YAAY,GAAI,YAAY,GAAI,OAEnE,IAAK,EAAE,OAAO,MAAA,EAAA,QAAA,EAAA,cAAA,eAEW,KAAA,WAAA,qCAE6B,CAAV,MAAU,KAAK,IAAQ,IAAQ,MAAA,qBAC3E,IAAI,QAAQ,GAAI,QAAQ;AAAA,SAGvB,cAAc,YAAY;;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;AAAA,QAK5B,KAAQ,KAAK,UAAU;AAAA,SAEtB,MAAM,KAAK,IAAI,KAAK,UAAU,eAChC,iCAAA,KACE,OAAO,KAAK,IAAI,KAAM;AAAA,QACvB,IAAU,KAAK,OAAO,cAAc,IAEpC,IAAU,KAAK,UAAU,cAAc;AAAA,QAExC,KAAK,OAAO;AAAA,QACN,MAAM,OAAA,gBAAA,KAA0B,KAAK,OAAA,OAAA,KACxC,OAAO;aACH,KAAK,OAAO,GAAS;AAAA,UAE1B,IAAA,gBADQ,MAAK,OAAO,KAAA;AAAA,QAEhB,MAAM,OAAO,GAAA,KAEhB,OAAO;;AAAA,QAEJ,MAAM,OAAA;OAAA,EAAA,KAAA,aAAA,OAAA,SAIN,IAAG,GAAA;AAAA,QAAG,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAAY,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA,IAAiB,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAA;AAAS,SAChD,YAAY,EAAM,MAAA,KAClB,aAAa,EAAM,OAAA,KACnB,aAAa,GAAA,KACb,IAAI,IAAA,KACJ,IAAI,GAAA,KACJ,kBAAkB,EAAM,cAAc,GAAA,KACtC,QAAQ,GAAA,KACR;OAAA,EAAA,KAAA,WAAA,OAAA,WAAA;AAAA,SAIA,UAAU,MAAM,MAAM,OAAA,KACtB,UAAU,MAAM,OAAO,OAAA,KACvB,UAAU,MAAM,UAAU;OAAA,EAAA,KAAA,WAAA,OAAA,WAAA;AAAA,SAI1B,UAAU,MAAM,MAAM,KAAK,MAAM,MAAA,KACjC,UAAU,MAAM,OAAO,KAAK,OAAO,MAAA,KACnC,UAAU,MAAM,UAAU;SAAA;;Ab1G1B,Ia0G0B,YAAA,AAAA,OAAA,UAAA,cAAA,AAAA,OAAA,OAAA,YAAA,WAAA,SAAA,IAAA;AAAA,SAAA,OAAA;IAAA,SAAA,IAAA;AAAA,SAAA,MAAA,AAAA,OAAA,UAAA,cAAA,GAAA,gBAAA,UAAA,OAAA,OAAA,YAAA,WAAA,OAAA;;Ab1G1B,IGlBD,mBAAA,EAAA,cACS,WAAA,MACN,WAAA,QACE,WAAA,KACH,WAAA,QACG,WAAA,QACA,WAAA,OACD,WAAA,eACM,WAAA,QACL,WAAA,SACC,WAAA,OACF,WAAA,MACD,WAAA,cACM,WAAA,aACD;AHIP,IG0BM,WAAW,SAAC,IAAA;AAAA,SAEpB,4BAA6B,KAAK,MAAA,8BACE,KAAK,IAC1C,IAAI,SAAC,IAAG,GAAA;AAAA,WAAa,AAAN,MAAM,IAAI,OAAO,IAAG,SAAS,MAAM;KAClD,OAAO,SAAC,IAAG,GAAA;AAAA,WAAA,KAAU,KAAI;OAErB,iBAAiB,OAAU;;AHjC5B,IGiC4B,iBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,QAAA,IAAA,IAAA,IAAA,MAAA,IAAA,OAAA,IAAA;AAAA,QAAA;AAAA,eAAA,GAAA,IAAA,GAAA,OAAA,aAAA,CAAA,KAAA,KAAA,EAAA,QAAA,SAAA,GAAA,KAAA,EAAA,QAAA,CAAA,KAAA,EAAA,WAAA,IAAA,IAAA;AAAA;aAAA,IAAA;AAAA,UAAA,MAAA,IAAA;cAAA;AAAA,UAAA;AAAA,SAAA,KAAA,EAAA,UAAA,EAAA;gBAAA;AAAA,YAAA;AAAA,gBAAA;;;AAAA,WAAA;;AAAA,SAAA,SAAA,GAAA,GAAA;AAAA,QAAA,MAAA,QAAA;AAAA,aAAA;AAAA,QAAA,OAAA,YAAA,OAAA;AAAA,aAAA,GAAA,GAAA;AAAA,UAAA,IAAA,UAAA;;;AHjC5B,IGiC4B,YAAA,AAAA,OAAA,UAAA,cAAA,AAAA,OAAA,OAAA,YAAA,WAAA,SAAA,IAAA;AAAA,SAAA,OAAA;IAAA,SAAA,IAAA;AAAA,SAAA,MAAA,AAAA,OAAA,UAAA,cAAA,GAAA,gBAAA,UAAA,OAAA,OAAA,YAAA,WAAA,OAAA;;AHjC5B,IIbM,mBAAmB;AJazB,IIZD,eAAe;AJYd,IIXD,kBAAkB;AJWjB,IIVM,YAAY;AJUlB,IITD,kBAAkB;AJSjB,IIRD,YAAY;AJQX,II0lBI,cAAA,EAAA,KACH,SAAC,IAAA;AAAA,MACH,IAAA;AACiB,EAAlB,GAAK,aAAa,UAAb,KACU,GAAK,aAAa,cAAA,KAC5B,GAAK,WAAW;AAAA,MAEpB,IAAU,GAAK;AAAA,SAAA,EACX,MAAM,OAAO,WAAA,EACb,MAAM,UAAU,OAErB,KAAA,EACM,aAAa,aAAa,IAE5B;GAAA,KAGD,SAAC,IAAA;AAAA,MACH,IAAA;AACiB,EAAlB,GAAK,aAAa,YAAb,KACU,GAAK,aAAa,cAAA,KAC5B,GAAK,WAAW;AAAA,MAEpB,IAAU,GAAK,aACf,IAAS,GAAK,aAAa,MAC3B,IAAO,GAAK,aAAa;AAAA,SAAA,EACrB,aAAa,KAAK,SAAS,KAAU,wBAAA,EACrC,aAAa,QAAQ,IAAA,EACrB,MAAM,UAAU,OAErB,KAAA,EACM,aAAa,aAAa,IAE5B;GAAA,aAGO,SAAC,IAAA;AAAA,MACX,IAAA;AACiB,EAAlB,GAAK,aAAa,YAAb,KACU,GAAK,aAAa,cAAA,KAC5B,GAAK,WAAW;AAAA,MAEpB,IAAU,GAAK,aACf,IAAS,GAAK,aAAa,MAC3B,IAAO,GAAK,aAAa;AAAA,SAAA,EACrB,aAAa,KAAK,SAAS,KAAU,wBAAA,EACrC,aAAa,QAAQ,IAAA,EACrB,MAAM,UAAU,OAErB,KAAA,EACM,aAAa,aAAa,IAE5B;;AJ9oBF,IIkpBI,gBAAA,EAAA,KACH,SAAC,IAAM,GAAA;AAAA,MACT,IAAA;AACiB,EAAlB,GAAK,aAAa,UAAb,KACU,GAAK,aAAa,cAAA,KAC5B,GAAK,WAAW;AAAA,MAEpB,IAAA,CAAc,KAAK,KAAK,SAAS;AAAA,SAC9B,OAAO,GAAK,YACjB,OAAO,SAAA,IAAA;AAAA,WAAQ,EAAW,SAAS,GAAK,SAAS,GAAK;KACtD,IAAI,SAAA,IAAA;AAAA,MACI,aAAa,GAAK,MAAM,GAAK;MAGpC,KAAA,EACM,aAAa,aAAa;GAAA,KAI7B,SAAC,IAAM,GAAA;AAAA,MACT,IAAA;AACiB,EAAlB,GAAK,aAAa,YAAb,KACU,GAAK,aAAa,cAAA,KAC5B,GAAK,WAAW;AAAA,MAEpB,IAAA,CAAc,MAAM;AAAA,SACjB,OAAO,GAAK,YACjB,OAAO,SAAA,IAAA;AAAA,WAAQ,EAAW,SAAS,GAAK,SAAS,GAAK;KACtD,IAAI,SAAA,IAAA;AAAA,MACI,aAAa,GAAK,MAAM,GAAK;MAGpC,KAAA,EACM,aAAa,aAAa;GAAA,aAIrB,SAAC,IAAM,GAAA;AAAA,MACjB,IAAA;AACiB,EAAlB,GAAK,aAAa,YAAb,KACU,GAAK,aAAa,cAAA,KAC5B,GAAK,WAAW;AAAA,MAEpB,IAAA,CAAc,MAAM;AAAA,SACjB,OAAO,GAAK,YACjB,OAAO,SAAA,IAAA;AAAA,WAAQ,EAAW,SAAS,GAAK,SAAS,GAAK;KACtD,IAAI,SAAA,IAAA;AAAA,MACI,aAAa,GAAK,MAAM,GAAK;MAGpC,KAAA,EACM,aAAa,aAAa;;AJrsB9B,IIqsB8B,mBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,QAAA,IAAA,IAAA,IAAA,MAAA,IAAA,OAAA,IAAA;AAAA,QAAA;AAAA,eAAA,GAAA,IAAA,GAAA,OAAA,aAAA,CAAA,KAAA,KAAA,EAAA,QAAA,SAAA,GAAA,KAAA,EAAA,QAAA,CAAA,KAAA,EAAA,WAAA,IAAA,IAAA;AAAA;aAAA,IAAA;AAAA,UAAA,MAAA,IAAA;cAAA;AAAA,UAAA;AAAA,SAAA,KAAA,EAAA,UAAA,EAAA;gBAAA;AAAA,YAAA;AAAA,gBAAA;;;AAAA,WAAA;;AAAA,SAAA,SAAA,GAAA,GAAA;AAAA,QAAA,MAAA,QAAA;AAAA,aAAA;AAAA,QAAA,OAAA,YAAA,OAAA;AAAA,aAAA,GAAA,GAAA;AAAA,UAAA,IAAA,UAAA;;;AJrsB9B,IKhBM,gBAAgB;ALgBtB,IKfM,gBAAgB;ALetB,IKdM,uBAAuB;ALc7B,IKbM,sBAAsB;ALa5B,IKXM,aAAa;ALWnB,IKXmB,mBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,QAAA,IAAA,IAAA,IAAA,MAAA,IAAA,OAAA,IAAA;AAAA,QAAA;AAAA,eAAA,GAAA,IAAA,GAAA,OAAA,aAAA,CAAA,KAAA,KAAA,EAAA,QAAA,SAAA,GAAA,KAAA,EAAA,QAAA,CAAA,KAAA,EAAA,WAAA,IAAA,IAAA;AAAA;aAAA,IAAA;AAAA,UAAA,MAAA,IAAA;cAAA;AAAA,UAAA;AAAA,SAAA,KAAA,EAAA,UAAA,EAAA;gBAAA;AAAA,YAAA;AAAA,gBAAA;;;AAAA,WAAA;;AAAA,SAAA,SAAA,GAAA,GAAA;AAAA,QAAA,MAAA,QAAA;AAAA,aAAA;AAAA,QAAA,OAAA,YAAA,OAAA;AAAA,aAAA,GAAA,GAAA;AAAA,UAAA,IAAA,UAAA;;;ALWnB,IMdD,SAAA,EAAA,MACC,mBAAA,QACE,WAAA,QAEA,iBAAA,SACC,cAAA,WACE;ANQL,IclBM,UAAU;AdkBhB,IclBgB,iBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,aAAA,IAAA,GAAA,IAAA,EAAA,QAAA,KAAA;AAAA,UAAA,IAAA,EAAA;AAAA,QAAA,aAAA,EAAA,cAAA,OAAA,EAAA,eAAA,MAAA,WAAA,KAAA,GAAA,WAAA,OAAA,OAAA,eAAA,IAAA,EAAA,KAAA;;;AAAA,SAAA,SAAA,GAAA,GAAA,GAAA;AAAA,WAAA,KAAA,GAAA,EAAA,WAAA,IAAA,KAAA,GAAA,GAAA,IAAA;;;AdkBhB,IeRc,YAAA,WAAA;AAAA,cACR,GAAQ,GAAA;AAAA,QAAA,kBAAA,MAAA,KAAA,IAET,UAAU,IAAA,KAEf,SAA2B,AAAA,OAAX,KAAW,WAC7B,SAAS,cAAc,KACvB,GAAA,CAEG,MAAK,kBAAkB;AAAA,YACtB,IAAI,MAAM;AAAA,SAGZ,eAAe,GAAA,KAEf,QAAQ,EAAQ,SAAS,IAAA,KACzB,OAAO,EAAQ,QAAQ,IAAA,KAEvB,WAAW,KAAK,YAAY,EAAQ,OAAA,KACpC,OAAO,KAAK,iBAAiB,KAAK,WAAA,KAElC,SAAS,KAAK,eAAe,EAAQ,QAAQ,KAAK,OAAA,KAElD,SAAA,EAAA,aACS,GAAA,YACD,GAAA,aACC,EAAQ,eAAe,GAAA,SAAA,AACnB,EAAQ,YADW,SACgB,EAAQ,UAAU,GAAA,iBACrD,EAAQ,mBAAmB,KAAA,KAGxC,WAAW,KAAK,MAAM,KAAK,UAAU;AAAA,QACtC,IAAI,KAAK;AAAA,SACR,YAAY,IACb,KAAK,MAAM,UAAA,GAAY,cAAc,IACrC,KAAK,OAAO,cAAY,GAAE,eAAe,IAAA,KACxC,YAAY,EAAQ,UAAU,EAAE,YAAA,KAEhC,QAAA,IAAA,KACA,UAAA,IAAA,KAEA,cAAc,2BAEhB,KAAK,OAAO,eAAA,MACT,WAAA,KAAA,KAGD,UAAU;;AAAA,SAAA,eAAA,IAAA,CAAA,EAAA,KAAA,eAAA,OAAA,SAGJ,IAAA;AAAA,WACJ;OAAA,EAAA,KAAA,oBAAA,OAAA,SAGS,IAAA;AAAA,WACT;OAAA,EAAA,KAAA,kBAAA,OAAA,SAGO,IAAQ,GAAA;AAAA,QAChB,IAAA;AAAA,WAAA,MACI,OAAA,IAAc,OAAO,eAAe,KACvC,QAAQ,SAAC,IAAA;AAAA,UACT,KAAQ,SAAS;AACnB,mBAAa,MAAA,EAGJ,KAAK,MAAA,QAFT,KAAK,MAAM,KAAS;QAKvB;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;OAAA,EAAA,KAAA,aAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MASH,IAAS,KAAK;AAAA,SACb,aAAa,GAAA,KACb,SAAS,IAAS,eAAe,KAAK,WAAA,KAGtC,cAAc,WAAA;AAAA,aAAM,GAAK,KAAA;OAC1B,kBAAA,MACE,iBAAiB,IAAI,eAAe,KAAK,cAAA,KACzC,eAAe,QAAQ,KAAK,UAAA,OAE3B,iBAAiB,UAAU,KAAK,cAAA,OAChC,iBAAiB,qBAAqB,KAAK;OAAA,EAAA,KAAA,WAAA,OAAA,WAAA;AAI9C,SAAK,kBAAgB,KAAK,eAAe,cAAA,OACtC,oBAAoB,UAAU,KAAK,cAAA,OACnC,oBAAoB,qBAAqB,KAAK;OAAA,EAAA,KAAA,SAAA,OAAA,WAAA;AAAA,SAKhD,iBAAA,KACA,eAAA,KACA,eAAA,KAEA,KAAA,OAAK;OAAO,EAAA,KAAA,iBAAA,OAAA,WAAA;AAAA,SAKZ,OAAO,YAAY;AAAA,QAEpB,KAAA,EAAA,QACK,KAAK,QAAA,WACF;AAGT,SAAK,oBAAA,IACF,SAAA,EAAW,OAAO,KAAK,mBAAmB,SAAA,KAG3C,YAAY,EAAE,OAAO,OAAO;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,SAI5B,MAAM,IAAI,OAAA,EAAA,QACN,KAAK,WAAA,QACL,KAAK,WAAA,KAET;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;OAAA,EAAA,KAAA,QAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MAKD,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA,IAAuB,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA;AACvB,SAAmB,SAAS,KAAK,WAAA,MAIhC,eAAA,KAEA,KAAK,IAAA,KACL,iBAAA,KACA,mBAAA,KAEA,WAAW,QAAQ,SAAA,IAAA;AAAA,aAAK,GAAE,MAAM,GAAK;QAAA,KAErC,OAAO,KAAK,YAAA,QAEd,KAAA,MACG,OAAO,KAAK,UAAA,WACN,WAAA;AAAA,SAAY,OAAO,GAAK;OAAS,KAAK,eAAA,KAG7C,gBAAA,KAEA,gBAAgB;OAAA,EAAA,KAAA,QAAA,OAAA,WAAA;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,SAMhB,YAAY,uBAAuB,KAAK,SAAA,KACxC,QAAQ,KAAK,YAAY,cAAc,KAAK;OAAA,EAAA,KAAA,iBAAA,OAAA,WAAA;AAI9C,SAAK,OAAA,KACF,UAAU,YAAY,KAAK;AAAA,QAE7B,KAAI,KAAK;AAAA,SAER,MAAM,iBACV,KAAK,WACL,sBACA,KAAK,WACL,KAAK,aAAA,KAED,UAAU,YAAY,KAAK,MAE7B,KAAK,MAAM,UAAA,MACR,UAAU,SACd,SACA,GAAE,QAAQ,MACV,GAAE,QAAQ,KACV,KAAK,OAAA,EAAA,UAEM,GAAE,eAAA,MACN,WAAA,IACF,GAAE;AAAA,QAKL,IAAM,aAAa;AAAA,SAClB,WAAW,aACf,KAAK,OAAO,0BAAA,eACC,cAAc,MAAA,OAAO,IAAA,MAGhC,KAAK,OAAO,cAAA,MACP,KAAK,SAAS,GAAE,SAAS,QAAA,KAC3B,aAAa,aACjB,gBAAA,eACa,cAAc,MAAA,OAAO,IAAA,OAIjC,KAAK,MAAM,UAAA,KAAe,IAAI,YAAY,KAAK,UAAA,KAC7C,IAAI,YAAY,KAAK,WACvB,KAAK,OAAO,cAAA,KAAmB,IAAI,YAAY,KAAK,aAAA,KAElD,gBAAgB,cAAc,KAAI,aAAa;OAAA,EAAA,KAAA,mBAAA,OAAA,SAGrC,IAAG,GAAA;AAAA,SACb,IAAI,SAAA,EAAA,GACL,IAAA,GACA;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;AAAA,SAIoB,aAAa,IAAI;OAAA,EAAA,KAAA,UAAA,OAAA,SAEnC,IAAA;AACF,UAAA,QACK,MAAM,uBAAA,KAEV,OAAO,KAAK,YAAY,KAAA,KACxB,QAAA,KACA,OAAO,KAAK,YAAY,KAAK,OAAO,UAAA,KACpC;OAAA,EAAA,KAAA,UAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MAGC,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAW,KAAK,YAAY,IAAA,CAAA,WAAA,SAAA,KAAA,AAAA,UAAA,OAAA,WAAA,UAAA;AAC/B,SAAK,OAAO,eAAA,KAET,SAAS,IAAI,SAAA,IAAA;AAAA,aAAK,GAAE,WAAW,YAAY;;AAAA,QAG7C,IAAA;AAAA,MAEO,QAAQ,SAAA,IAAA;AAAA,UACE,EAAkB,OAAO,GAAE,OAAO;QAEpD,EAAkB,SAAS,IAAA,kBACZ,KAAK,WAAW,KAAK,KAAK,IAAA,WAChC,WAAA;AAAA,QACC,QAAQ,SAAA,IAAA;AAAA,eAAK,GAAE;UAAA,GACrB;OACH,+BAAA,GAEQ,QAAQ,SAAA,IAAA;AAAA,aAAK,GAAE;QAAA,KACrB;OAAA,EAAA,KAAA,aAAA,OAAA,WAAA;AAKH,SAAK,OAAO,eAAA,MACT,eAAA,KACA;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MAMS,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA;AACX,SAAK,OAAO,eAEb,KAAA,MACG,eAAA,KAEA,aAAA,EAAA,IACE,KAAK,WAAW,KAAK,OAAA,IACrB,KAAK,YAAY,KAAK,OAAA,IACtB,KAAK,UAAU,KAAK,OAAA,IACpB,KAAK,aAAa,KAAK,OAAA,IACvB,KAAK,YAAY,KAAK,SAAA,SAGpB,iBAAiB,WAAW,SAAC,IAAA;AAClC,0BAAoB,GAAK,cAAA,MACvB,MAAK,OAAO,OACb,GAAK,WAAW,GAAE,YAAA,GACf,WAAW,GAAE;;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;OAAA,EAAA,KAAA,iBAAA,OAAA,WAAA;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;OAAA,EAAA,KAAA,aAAA,OAAA,WAAA;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;OAAA,EAAA,KAAA,aAAA,OAAA,WAAA;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;OAAA,EAAA,KAAA,cAAA,OAAA,WAAA;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;OAAA,EAAA,KAAA,uBAAA,OAAA,WAAA;OAAA,EAAA,KAAA,iBAAA,OAAA,WAAA;OAAA,EAAA,KAAA,UAAA,OAAA,WAAA;AAAA,QA2BlB,KAAW,iBAAiB,KAAK;AAAA,iBACxB,KAAK,SAAS,SAAA,CAAU;SAAA;;Af/ShC,Ie+SgC,iBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,aAAA,IAAA,GAAA,IAAA,EAAA,QAAA,KAAA;AAAA,UAAA,IAAA,EAAA;AAAA,QAAA,aAAA,EAAA,cAAA,OAAA,EAAA,eAAA,MAAA,WAAA,KAAA,GAAA,WAAA,OAAA,OAAA,eAAA,IAAA,EAAA,KAAA;;;AAAA,SAAA,SAAA,GAAA,GAAA,GAAA;AAAA,WAAA,KAAA,GAAA,EAAA,WAAA,IAAA,KAAA,GAAA,GAAA,IAAA;;;Af/ShC,Ie+SgC,SAAA,WAAA,GAAA,GAAA,GAAA;AAAA,EAAA,MAAA,QAAA,KAAA,SAAA;AAAA,MAAA,IAAA,OAAA,yBAAA,GAAA;AAAA,MAAA,AAAA,MAAA,QAAA;AAAA,QAAA,IAAA,OAAA,eAAA;AAAA,WAAA,AAAA,MAAA,OAAA,SAAA,EAAA,GAAA,GAAA;;AAAA,MAAA,WAAA;AAAA,WAAA,EAAA;AAAA,MAAA,IAAA,EAAA;AAAA,MAAA,AAAA,MAAA;AAAA,WAAA,EAAA,KAAA;;Af/ShC,IgBZc,mBAAA,SAAA,IAAA;AAAA,aACR,IAAQ,GAAA;AAAA,WAAA,kBAAA,MAAA,IAAA,6BAAA,MAAA,GAAA,aAAA,OAAA,eAAA,IAAA,KAAA,MACb,IAAQ;;AAAA,SAAA,YAAA,GAAA,KAAA,eAAA,GAAA,CAAA,EAAA,KAAA,aAAA,OAAA,SAGL,IAAA;AAAA,WAAA,EAAA,UAAA,aAAA,OAAA,eAAA,EAAA,YAAA,aAAA,MAAA,KAAA,MACO,KAAA,KAEX,OAAO,iBAAkB,IAAK,kBAAA,IAAsB,gBAAA,KACpD,OAAO,YAAY,GAAK,aAAa,IAAA,KACrC,OAAO,kBAAkB,GAAK,mBAAmB;OAAA,EAAA,KAAA,QAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MAIlD,KAAI,KAAK,OACT,IAAY,KAAK,OAAO;AAAA,OAC1B,cAAA;AAAA,QAEE,IAAY,KAAK,KAAK,OAAO,IAAI,SAAC,IAAO,IAAA;AAAA,UACxC,KAAQ;AAAA,aAAA,GACP,KAAK,SAAS,IAAI,SAAA,IAAA;AAAA,cACb,GAAE,OAAO;UAAA,CAEX,IAAO;OACb,OAAO,SAAA,IAAA;AAAA,aAAc,GAAE,MAAM;QAE5B,IAAS;AAAA,QACV,EAAU,SAAS,GAAW;AAAA,QAEtB,KAAK,SAAC,IAAG,IAAA;AAAA,eAAe,GAAE,KAAK,GAAE;UAAA,IAElC,EAAU,MAAM,GAAG,IAAU;AAAA,UAGlC,IAAiB;AAFL,QAAU,MAAM,IAAU,GAGhC,IAAI,SAAA,IAAA;AAAA,aAAwB,GAAE;UAAA,EACjC,KAAA,CAAM,GAAgB,UAAA,KACxB,OAAO,IAAU,KAAK;;AAAA,OAG1B,SAAA,IAAA,EACK,IAAI,SAAA,IAAA;AAAA,SACR,YAAY,KAAK,MAAM,GAAE,MAAA,GACzB,OAAO,KAAK,GAAE;QAAA,GAGf,aAAa,GAAE,YAAY,OAAO,SAAC,IAAG,IAAA;AAAA,aAAM,KAAI;OAAG,IAAA,KAEhD,SAAA,EAAA,GACD,KAAK,QAAQ,GAAA,GACb,KAAK,SAAS;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MAKd,KAAI,KAAK;AAAA,SACR,WAAW,cAAc,IAAA,KACzB,eAAe,GAAE,YAAY,MAAM,GAAG,KAAK,OAAO;AAAA,QAEnD,IAAQ,GACR,IAAI;AAAA,SACH,aAAa,IAAI,SAAC,GAAG,GAAA;AAAA,UACrB,IAAW,KACX,IAAU,KAAK,MACjB,IAAK,QAAQ,cAAc,GAAK,aAAW;AAEzC,SAAK,aAAa,SAAS,KAAA,KACnB,GAAK,QAAM,GAAK,aAAa,SAEtC,IAAQ,KAAA,KACF,GAAA,KACH;AAAA,UAEF,IAAI,IAAW,IAAQ,GACvB,IAAQ,GAAK,OAAO,kBAAkB,eAAe,GAAE,OAAO,IAAI,IAAS,MAAM,GAAE,OAAO,IAC1F,IAAY,GAAK,OAAO,iBAAiB,GAAK,OAAO,eAAe,KAAK,GACzE,IAAM,UACT,GACA,GACA,GACA,GAAK,OAAO,IACT,IAAA,OAAU,GAAA;AACb,SAEI,WAAW,YAAY,IAAA;;SAAA;EApFe;AhBYvC,IQhBM,oBAAoB;ARgB1B,IQfM,qBAAqB;ARe3B,IQbM,eAAe;ARarB,IQZM,aAAa;ARYnB,IQVM,cAAA,CAAe,WAAW,YAAY,SAAS,SAAS,OACpE,QAAQ,QAAQ,UAAU,aAAa,WAAW,YAAY;ARSxD,IQLM,kBAAA,CAAmB,OAAO,OAAO,OAAO,OAAO,OAAO,OAAO;ARKnE,IQLmE,mBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,QAAA,IAAA,IAAA,IAAA,MAAA,IAAA,OAAA,IAAA;AAAA,QAAA;AAAA,eAAA,GAAA,IAAA,GAAA,OAAA,aAAA,CAAA,KAAA,KAAA,EAAA,QAAA,SAAA,GAAA,KAAA,EAAA,QAAA,CAAA,KAAA,EAAA,WAAA,IAAA,IAAA;AAAA;aAAA,IAAA;AAAA,UAAA,MAAA,IAAA;cAAA;AAAA,UAAA;AAAA,SAAA,KAAA,EAAA,UAAA,EAAA;gBAAA;AAAA,YAAA;AAAA,gBAAA;;;AAAA,WAAA;;AAAA,SAAA,SAAA,GAAA,GAAA;AAAA,QAAA,MAAA,QAAA;AAAA,aAAA;AAAA,QAAA,OAAA,YAAA,OAAA;AAAA,aAAA,GAAA,GAAA;AAAA,UAAA,IAAA,UAAA;;;ARKnE,IQLmE,iBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,aAAA,IAAA,GAAA,IAAA,EAAA,QAAA,KAAA;AAAA,UAAA,IAAA,EAAA;AAAA,QAAA,aAAA,EAAA,cAAA,OAAA,EAAA,eAAA,MAAA,WAAA,KAAA,GAAA,WAAA,OAAA,OAAA,eAAA,IAAA,EAAA,KAAA;;;AAAA,SAAA,SAAA,GAAA,GAAA,GAAA;AAAA,WAAA,KAAA,GAAA,EAAA,WAAA,IAAA,KAAA,GAAA,GAAA,IAAA;;;ARKnE,ISXD,iBAAA,WAAA;AAAA,cAAA,GAAA;AAAA,QAAA,IAAA,EAEJ,YAAA,IAAA,AAAA,MAAA,SAAa,KAAA,GAAA,IAAA,EACb,gBAAA,IAAA,AAAA,MAAA,SAAiB,KAAA,GACjB,IAAA,EAAA,WAEA,IAAA,EAAA,SACA,IAAA,EAAA,cACA,IAAA,EAAA;AAAA,sBAAA,MAAA,KAAA,KAEK,iBAAiB,GAAA,KACjB,YAAY,GAAA,KAEZ,eAAe,GAAA,KACf,UAAU,GAAA,KAEV,kBAAkB,GAAA,KAElB,QAAA,IAAA,KACA,SAAA,IAAA,KAEA,aAAa,GAAA,KACb,aAAyC,AAAA,OAArB,KAAK,cAAgB,aAC3C,KAAK,eAAe,KAAK,YAAA,KAEvB;;AAAA,SAAA,eAAA,IAAA,CAAA,EAAA,KAAA,WAAA,OAAA,SAGE,IAAA;AAAA,SACF,OAAO,MAAQ,KAAK;OAAA,EAAA,KAAA,SAAA,OAAA,SAGpB,IAAA;AAAA,SACA,QAAQ,aAAa,KAAK,YAAY,KAAK,gBAAgB;OAAA,EAAA,KAAA,QAAA,OAAA,WAAA;AAAA,SAI3D,OAAO,KAAK,OAAA,KACZ,UAAU,KAAK;OAAA,EAAA,KAAA,UAAA,OAAA,SAGd,IAAA;AAAA,QAAA,IAAA;AAAA,SACD,QAAQ,KAAK,aAAa,KAAA,KAE1B,MAAM,cAAc,IAAA,KACpB,MAAM,QAAQ,SAAA,IAAA;AAAA,QACb,MAAM,YAAY;QAAA,KAEnB,OAAO,QAAQ,SAAA,IAAA;AAAA,QACd,MAAM,YAAY;;OAAA,EAAA,KAAA,UAAA,OAAA,WAAA;AAAA,QAIlB,KAAA,CAAA,WAAA,SAAA,KAAA,AAAA,UAAA,OAAA,WAAA,UAAA;AAAA,SACD;AAAA,QACD,IAAA;AAAA,WACD,MAAA,KACgB,KAAK,gBAAgB,KAAK,SAAA,KAEtC;SAAA;;AThDF,ISoDH,mBAAA,EAAA,aAAA,EAAA,YAEU,gBAAA,cAAA,SACC,IAAA;AAAA,SACL,GAAK,aAAa,IAAI,SAAC,GAAG,GAAA;AAAA,QAC5B,IAAQ,SAAS,GAAG,cAAc,GAAK,OAAO,IAAI,QAAQ,GAAK;AAAA,WAAA,EAC7D,MAAM,aAAa,kBAClB;;GAAA,iBAAA,SAIO,IAAA;AAAA,SACR,KAAK,MAAM,IAAI,SAAC,GAAO,GAAA;AAAA,WAAM,eAAe,GAAO,GAAQ,aAAa;;KAAA,WAAA,EAAA,YAIpE,cAAA,cAAA,SACC,IAAA;AAAA,SACL,GAAK,aAAa,IAAI,SAAC,GAAG,GAAA;AAAA,QAC5B,IAAQ,SAAS,GAAG,YAAY,QAAQ,GAAK,OAAO;AAAA,WAAA,EAClD,MAAM,aAAa,kBAClB;;GAAA,iBAAA,SAIO,IAAA;AAAA,SACR,KAAK,MAAM,IAAI,SAAC,GAAO,GAAA;AAAA,WAC7B,eAAe,GAAO,GAAQ,aAAa;;KAAA,gBAAA,EAAA,YAKjC,mBAAA,cAAA,SACC,IAAA;AAAA,MAAA,IAAA;AAAA,SACL,GAAK,WAAW,IAAI,SAAC,GAAG,GAAA;AAAA,WAEpB,cAAc,GADhB,GACsB,GAAK,OAAO,IACzC,EAAK,UAAU,WAAW,EAAK,UAAU,UAAU,GAAK,OAAO;;GAAA,iBAAA,SAKlD,IAAA;AAAA,MACZ;AAAS,WAAA;KAAA,OAAA,EAAA,YAID,UAAA,cAAA,SACC,IAAA;AAAA,MAAA,IAAA;AAAA,SACL,GAAK,UAAU,IAAI,SAAC,GAAU,GAAA;AAAA,WACpC,MAAM,GAAU,GAAK,OAAO,IAAI,EAAK,UAAU,OAAA,EAC7C,MAAM,EAAK,UAAU,MAAM,KAAK,EAAK,UAAU,KAAK,gBAAgB,EAAK,UAAU;;GAAA,iBAAA,SAIvE,IAAA;AAAA,MACX,IAAS,GAAQ,WACjB,IAAY,GAAQ,QACpB,IAAS,KAAK,QAAQ,WACtB,IAAY,KAAK,QAAQ,QAAA,IAEV,qBAAqB,GAAQ,IAAA,IAAA,iBAAA,GAAA;AAAA,MAAA,EAAA,IAAA,IAAA,EAAA;AAAA,MAAA,IACvB,qBAAqB,GAAW,IAAA,IAAA,iBAAA,GAAA;AAAA,SAAA,IAAA,EAAA,IAAA,IAAA,EAAA,IAAA,KAEpD,OAAA,EAAA,WACO,GAAA,QACH,MAGF,KAAK,MAAM,IAAI,SAAC,IAAM,IAAA;AAAA,WACrB,kBACN,IAAM,EAAO,KAAI,EAAO;;KAAA,OAAA,EAAA,YAOf,UAAA,cAAA,SACC,IAAA;AAAA,MAAA,IAAA;AAAA,SACL,GAAK,UAAU,IAAI,SAAC,GAAU,GAAA;AAAA,WACpC,MAAM,GAAU,GAAK,WAAW,IAAI,EAAK,UAAU,QAAA,EACjD,MAAM,EAAK,UAAU,MAAM,KAAK,EAAK,UAAU;;GAAA,iBAAA,SAInC,IAAA;AAAA,MACX,IAAS,GAAQ,WACjB,IAAY,GAAQ,YACpB,IAAS,KAAK,QAAQ,WACtB,IAAY,KAAK,QAAQ,YAAA,IAEV,qBAAqB,GAAQ,IAAA,IAAA,iBAAA,GAAA;AAAA,MAAA,EAAA,IAAA,IAAA,EAAA;AAAA,MAAA,IACvB,qBAAqB,GAAW,IAAA,IAAA,iBAAA,GAAA;AAAA,SAAA,IAAA,EAAA,IAAA,IAAA,EAAA,IAAA,KAEpD,OAAA,EAAA,WACO,GAAA,YACC,MAGN,KAAK,MAAM,IAAI,SAAC,IAAM,IAAA;AAAA,WACrB,kBACN,IAAM,EAAO,KAAI,EAAO;;KAAA,UAAA,EAAA,YAOf,aAAA,cAAA,SACC,IAAA;AAAA,MAAA,IAAA;AAAA,SACL,GAAK,IAAI,SAAA,IAAA;AAAA,WACf,QAAQ,GAAE,UAAU,GAAE,OAAO,EAAK,UAAU,OAAA,EAC1C,UAAU,GAAE,QAAQ,UAAU,MAAM,QAAQ,UAAU;;GAAA,iBAAA,SAG1C,IAAA;AAAA,MAAA,IACW,qBAAqB,KAAK,SAAS,KAAA,IAAA,iBAAA,GAAA;AAAA,OAAvD,UAAA,EAAA;AAAA,MAEF,IAAA,MAAA,EAAA,IAAiB,IAAI,SAAA,IAAA;AAAA,WAAK,GAAE;MAC5B,IAAY,GAAQ,IAAI,SAAA,IAAA;AAAA,WAAK,GAAE;MAC/B,IAAa,GAAQ,IAAI,SAAA,IAAA;AAAA,WAAK,GAAE;MAEhC,IAAS,KAAK,QAAQ,IAAI,SAAA,IAAA;AAAA,WAAK,GAAE;;AAAA,SAAA,KAEhC,OAAO,EAAO,IAAI,SAAC,IAAK,IAAA;AAAA,WAAA,EAAA,UAEjB,EAAO,KAAA,OACV,EAAU,KAAA,SACR,EAAW;OAIf,KAAK,MAAM,IAAI,SAAC,IAAM,IAAA;AAAA,WACrB,kBACN,IAAM,EAAO,KAAI,EAAO;;KAAA,UAAA,EAAA,YAOf,aAAA,cAAA,SACC,IAAA;AAAA,MAAA,IAAA;AAAA,SACL,GAAK,IAAI,SAAA,IAAA;AAAA,WACf,QAAQ,GAAE,UAAU,GAAE,QAAQ,EAAK,UAAU,OAC5C,GAAE,OAAA,EAAQ,UAAU,GAAE,QAAQ;;GAAA,iBAAA,SAGjB,IAAA;AAAA,MAAA,IACW,qBAAqB,KAAK,SAAS,KAAA,IAAA,iBAAA,GAAA;AAAA,OAAvD,UAAA,EAAA;AAAA,MAEF,IAAA,MAAA,EAAA,IAAiB,IAAI,SAAA,IAAA;AAAA,WAAK,GAAE;MAC5B,IAAY,GAAQ,IAAI,SAAA,IAAA;AAAA,WAAK,GAAE;MAC/B,IAAY,GAAQ,IAAI,SAAA,IAAA;AAAA,WAAK,GAAE;MAC/B,IAAa,GAAQ,IAAI,SAAA,IAAA;AAAA,WAAK,GAAE;MAEhC,IAAS,KAAK,QAAQ,IAAI,SAAA,IAAA;AAAA,WAAK,GAAE;MACjC,IAAY,KAAK,QAAQ,IAAI,SAAA,IAAA;AAAA,WAAK,GAAE;;AAAA,OAEnC,OAAO,EAAO,IAAI,SAAC,IAAK,IAAA;AAAA,WAAA,EAAA,UAEjB,EAAU,KAAA,QACZ,EAAO,KAAA,OACR,EAAU,KAAA,SACR,EAAW;;AAAA,MAIlB,IAAA;AAAA,SAAA,KAEC,MAAM,IAAI,SAAC,IAAW,IAAA;AAAA,QACR,EAAgB,OAAO,cACxC,IAAW,EAAU,KAAI,EAAO,KAAI,EAAO;MAItC;KAAA,YAAA,EAAA,YAKI,WAAA;AAAA,SAAoB,wBAAwB,KAAK,UAAU;GAAA,cAAA,SAC1D,IAAA;AAAA,MAAA,IAAA,MAAA,IACuD,KAAK,WAAnE,IAAA,EAAA,OAAO,IAAA,EAAA,UAAU,IAAA,EAAA,WAAW,IAAA,EAAA,YAAY,IAAA,EAAA,QAEzC,IAAA,EAFiD,YAEjC,IAAI;AAAA,SAAA,KAEnB,uBAAA,IAAA,GAEA,KAAK,IAAI,SAAC,IAAM,IAAA;AACN,IAAX,OAAW,KAAX,EACG,OAAO,KACX,SAAS,eAAe,GAAA,KAAoB,aAAa,GAAA,MAAa,eAAA,EAAA,UAE1D,OAAA,GAKT,IAAI,SAAC,IAAK,IAAA;AAAA,UACX,GAAI,MAAM;AAAA,YACR,KAAA,EAAA,aACU,GAAI,UAAA,cACH,GAAI,WAAA,YACN,MAET,KAAS,WAAW,OAAO,GAAG,GAAG,GAAY,GAAQ,GAAI,MAAM;AAAA,UAC9D,qBAAqB,KAAK;;AAAA,WAE3B;QAAA,IAEF,GAAA,KACC;MAGC,KAAK;GAAA,iBAAA,SAGG,IAAA;AAAA,MACZ;AAAS,WAAA;KAAA,UAAA,EAAA,YAKD,WAAA;AAAA,SAAoB,wCAAwC,KAAK,UAAU;GAAA,cAAA,SAC1E,IAAA;AAAA,MACR,IAAI,KAAK;AAAA,SAAA,KACR,WAAW,OAAA,KACX,QAAQ,GAAK,WAAW,IAAI,SAAC,GAAG,GAAA;AAAA,WAC7B,WACN,GAAK,WAAW,IAChB,GACA,GAAK,UACL,EAAE,OACF,GAAK,OAAO,IACZ,GACA,GAAK,QAAQ,IAAA,EAAA,UAEF,GAAK,UAAA,WACJ,GAAK,WAAA,WACL,EAAE;MAIT,KAAK;GAAA,iBAAA,SAEG,IAAA;AAAA,MACX,IAAU,GAAQ,YAClB,IAAU,GAAQ,YAClB,IAAa,GAAQ,SACrB,IAAY,GAAQ,QAEpB,IAAU,KAAK,QAAQ,YACvB,IAAU,KAAK,QAAQ,YACvB,IAAa,KAAK,QAAQ,SAC1B,IAAY,KAAK,QAAQ,QAAA,IAER,qBAAqB,GAAS,IAAA,IAAA,iBAAA,GAAA;AAAA,MAAA,EAAA,IAAA,IAAA,EAAA;AAAA,MAAA,IAC9B,qBAAqB,GAAS,IAAA,IAAA,iBAAA,GAAA;AAAA,MAAA,EAAA,IAAA,IAAA,EAAA;AAAA,MAAA,IACxB,qBAAqB,GAAY,IAAA,IAAA,iBAAA,GAAA;AAAA,MAAA,EAAA,IAAA,IAAA,EAAA;AAAA,MAAA,IACnC,qBAAqB,GAAW,IAAA,IAAA,iBAAA,GAAA;AAAA,MAAA,EAAA,IAAA,IAAA,EAAA,IAAA,KAEpD,OAAA,EAAA,YACQ,GAAA,YACA,GAAA,SACH,GAAA,QACD,GAAA,UAEE,KAAK,QAAQ,UAAA,WACZ,KAAK,QAAQ,WAAA,UACd,KAAK,QAAQ;AAAA,MAGpB,IAAA;AAAA,SAAA,KAEC,MAAM,IAAI,SAAC,IAAK,IAAA;AAAA,QACF,EAAgB,OAAO,WACxC,IAAK,EAAQ,KAAI,EAAQ,KAAI,GAAQ,UAAU,EAAW,KAAA,EACzD,UAAU,GAAQ;MAId;KAAA,WAAA,EAAA,YAKI,WAAA;AAAA,SAAoB,wCAAwC,KAAK,UAAU;GAAA,cAAA,SAC1E,IAAA;AAAA,MACR,IAAI,KAAK;AAAA,SAAA,KACR,WAAW,OAAA,KACX,QAAA,IACD,EAAE,YAAA,MACA,QAAQ,SACZ,GAAK,YACL,GAAK,YACL,EAAE,OAAA,EAAA,UAES,EAAE,UAAA,YACA,EAAE,YAAA,QACN,EAAE,UAAA,EAAA,SAGD,EAAE,SAAA,UACD,GAAK,cAAA,KAKb,QAAA,IACD,EAAE,YAAA,MACA,QAAQ,GAAK,WAAW,IAAI,SAAC,GAAG,GAAA;AAAA,WAC7B,WACN,GAAK,WAAW,IAChB,GACA,GAAK,QACL,EAAE,OACD,EAAE,mBAAmB,GAAK,OAAO,KAAK,IACvC;OAKI,OAAO,OAAO,KAAK,OAAO,OAAO,KAAK;GAAA,iBAAA,SAE9B,IAAA;AAAA,MACX,IAAU,GAAQ,YAClB,IAAU,GAAQ,YAClB,IAAY,GAAQ,QAEpB,IAAU,KAAK,QAAQ,YACvB,IAAU,KAAK,QAAQ,YACvB,IAAY,KAAK,QAAQ,QAAA,IAER,qBAAqB,GAAS,IAAA,IAAA,iBAAA,GAAA;AAAA,MAAA,EAAA,IAAA,IAAA,EAAA;AAAA,MAAA,IAC9B,qBAAqB,GAAS,IAAA,IAAA,iBAAA,GAAA;AAAA,MAAA,EAAA,IAAA,IAAA,EAAA;AAAA,MAAA,IAC1B,qBAAqB,GAAW,IAAA,IAAA,iBAAA,GAAA;AAAA,MAAA,EAAA,IAAA,IAAA,EAAA,IAAA,KAEpD,OAAA,EAAA,YACQ,GAAA,YACA,GAAA,QACJ,GAAA,UAEE,KAAK,QAAQ,UAAA,QACf,KAAK,QAAQ;AAAA,MAGlB,IAAA;AAAA,SAED,OAAO,KAAK,KAAK,OAAO,UAAA,KACR,EAAgB,OAAO,YACxC,KAAK,OAAO,GAAS,GAAS,GAAQ,UAAU,KAAK,UAAU,WAG9D,KAAK,MAAM,UAAA,KACR,MAAM,IAAI,SAAC,IAAK,IAAA;AAAA,QACF,EAAgB,OAAO,WACxC,IAAK,EAAQ,KAAI,EAAQ;MAIrB;;AT9ZH,IS8ZG,eAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,aAAA,IAAA,GAAA,IAAA,EAAA,QAAA,KAAA;AAAA,UAAA,IAAA,EAAA;AAAA,QAAA,aAAA,EAAA,cAAA,OAAA,EAAA,eAAA,MAAA,WAAA,KAAA,GAAA,WAAA,OAAA,OAAA,eAAA,IAAA,EAAA,KAAA;;;AAAA,SAAA,SAAA,GAAA,GAAA,GAAA;AAAA,WAAA,KAAA,GAAA,EAAA,WAAA,IAAA,KAAA,GAAA,GAAA,IAAA;;;AT9ZH,IS8ZG,OAAA,YAAA,GAAA,GAAA,GAAA;AAAA,EAAA,MAAA,QAAA,KAAA,SAAA;AAAA,MAAA,IAAA,OAAA,yBAAA,GAAA;AAAA,MAAA,AAAA,MAAA,QAAA;AAAA,QAAA,IAAA,OAAA,eAAA;AAAA,WAAA,AAAA,MAAA,OAAA,SAAA,GAAA,GAAA,GAAA;;AAAA,MAAA,WAAA;AAAA,WAAA,EAAA;AAAA,MAAA,IAAA,EAAA;AAAA,MAAA,AAAA,MAAA;AAAA,WAAA,EAAA,KAAA;;AT9ZH,IiBbc,kBAAA,SAAA,IAAA;AAAA,aACR,IAAQ,GAAA;AAAA,sBAAA,MAAA;AAAA,QAAA,IAAA,2BAAA,MAAA,GAAA,aAAA,OAAA,eAAA,IAAA,KAAA,MACb,IAAQ;AAAA,WAAA,EACT,OAAO,cAAA,EACP,SAAA;;AAAA,SAAA,UAAA,GAAA,KAAA,aAAA,GAAA,CAAA,EAAA,KAAA,eAAA,OAAA,SAGM,IAAA;AAAA,QACP,KAAI,KAAK;AAAA,SACR,aAAa,GAAQ,cAAA;AAAA,QAEtB,IAAI,KAAK;AAAA,MACX,SAAS,EAAE,UAAU,+BAAA,EACrB,QAAQ,EAAE,SAAS,8BAAA,GAEnB,SAAS,QAAQ,IAAA,GACjB,eAAe,IAAA,GACf,aAA0C,IAA5B,GAAE,SAAmB,MAAV,EAAE;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;AAAA,QAIzB,KAAI,KAAK,OAET,KAAA,CAAA,CAEF,kBAAA,EAAA,WAEY,KAAK,WAAW,QAAA,UACjB,KAAK,WAAW,SAE3B,WAAA;AAAA,aAAA,EAAA,YAEc,GAAE,YAAA,QACN,GAAE,QAAA,QACF,KAAK;MAEb,KAAK;AAAA,SAIJ,aAAa,IAAI,IAAI,GACxB,IAAI,SAAA,IAAA;AAAA,UACA,KAAY,aAAA,MAAA,QAAA,mBAAgB;AAAA,aAAA,CACxB,GAAK,IAAI;;OAAA,EAAA,KAAA,QAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,SAAA,EAAA,UAAA,aAAA,OAAA,eAAA,EAAA,YAAA,QAAA,MAAA,KAAA;AAAA,QAMf,IAAI,KAAK;AAAA,MAEX,aAAA,IAAA,EACA,SAAA;AAAA,QAEE,IAAO;AAAA,MACT,YAAY,IAAI,SAAC,IAAA;AAAA,UACd,IAAQ,GAAK,QAAQ,KAAQ,EAAE;AAAA,QACjC,OAAO,KAAK,IAAA,EACZ,WAAW,KAAK,IAAA,KACV;;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MAOL,KAAI,KAAK;AAAA,SACR,UAAU,iBAAiB,aAAa,SAAC,GAAA;AAAA,UACzC,IAAO,GAAK,WAAW,IAAI,kBAAkB,OAC7C,IAAM,EAAE;AAAA,UACT,EAAK,SAAS,IAAM;AAAA,YAElB,IAAI,EAAK,QAAQ,IACjB,IAAO,UAAU,GAAK,YAAY,IAAO,UAAU,IAEnD,IAAI,EAAK,OAAO,EAAK,OAAO,SAAS,EAAI,aAAa,YAAU,GAChE,IAAI,EAAK,MAAM,EAAK,KACpB,IAAS,IAAK,mBAAmB,GAAK,gBAAgB,SAAO,IAC9D,GAAK,gBAAgB,KAAK,GAAK,MAAM,OAAO,MAAM,MACjD,IAAW,GAAE,YAAY,KAAG,GAAE;AAAA,WAE7B,IAAI,UAAU,GAAG,GAAA,EAAI,MAAM,GAAO,OAAiB,OAAT,GAAc,QAAQ,KAAK,QAAA,GACrE,IAAI;;;SAAA;EAlFgC;AjBatC,IiBbsC,iBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,aAAA,IAAA,GAAA,IAAA,EAAA,QAAA,KAAA;AAAA,UAAA,IAAA,EAAA;AAAA,QAAA,aAAA,EAAA,cAAA,OAAA,EAAA,eAAA,MAAA,WAAA,KAAA,GAAA,WAAA,OAAA,OAAA,eAAA,IAAA,EAAA,KAAA;;;AAAA,SAAA,SAAA,GAAA,GAAA,GAAA;AAAA,WAAA,KAAA,GAAA,EAAA,WAAA,IAAA,KAAA,GAAA,GAAA,IAAA;;;AjBatC,IiBbsC,SAAA,YAAA,GAAA,GAAA,GAAA;AAAA,EAAA,MAAA,QAAA,KAAA,SAAA;AAAA,MAAA,IAAA,OAAA,yBAAA,GAAA;AAAA,MAAA,AAAA,MAAA,QAAA;AAAA,QAAA,IAAA,OAAA,eAAA;AAAA,WAAA,AAAA,MAAA,OAAA,SAAA,GAAA,GAAA,GAAA;;AAAA,MAAA,WAAA;AAAA,WAAA,EAAA;AAAA,MAAA,IAAA,EAAA;AAAA,MAAA,AAAA,MAAA;AAAA,WAAA,EAAA,KAAA;;AjBatC,IkBTc,WAAA,SAAA,IAAA;AAAA,aACR,IAAQ,GAAA;AAAA,sBAAA,MAAA;AAAA,QAAA,IAAA,6BAAA,MAAA,GAAA,aAAA,OAAA,eAAA,IAAA,KAAA,MACb,IAAQ;AAAA,WAAA,EACT,OAAO,OAAA,EACP,cAAc,GAAA,EACd,OAAO,GAAA,EAEP,SAAA;;AAAA,SAAA,YAAA,GAAA,KAAA,eAAA,GAAA,CAAA,EAAA,KAAA,aAAA,OAAA,SAGI,IAAA;AAAA,WAAA,EAAA,UAAA,aAAA,OAAA,eAAA,EAAA,YAAA,aAAA,MAAA,KAAA,MACO,KAAA,KACX,YAAY,KAAK,UAAU,KAAK,OAAA,KAChC,aAAa,KAAK,WAAW,KAAK,OAAA,KAElC,aAAa,GAAK,cAAc,KAAA,KAChC,OAAO,aAAa,GAAK,cAAc,GAAA,KAEvC,YAAY,GAAK,aAAA;OAAa,EAAA,KAAA,QAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,WAAA,EAAA,UAAA,aAAA,OAAA,eAAA,EAAA,YAAA,QAAA,MAAA,KAAA;AAAA,QAK/B,IAAI,KAAK;AAAA,SACR,SAAU,KAAK,SAAS,KAAK,QAAQ,KAAK,OAAO,IAAI,KAAK,OAAO;AAAA,QAE9D,IAAsB,KAAtB,QAAQ,IAAc,KAAd,WAEV,IAAuB,EAAE,oBAAA;AAAA,MAC7B,eAAA,IAAA,EACA,mBAAA;AAAA,QACE,IAAW,MAAM,KAAK,OAAO;AAAA,MAC/B,YAAY,IAAI,SAAC,IAAO,GAAA;AAAA,UACnB,IAAa,GACb,IAAmB,KAAQ,EAAE,aAAc,YAC3C,IAAW,IAAkB,MAAM,IAAG,GACtC,IAAY,IAAA,CAAa,IAAkB,GAC3C,IAAW,KAAsB,GACjC,IAAgB,mBAAmB,GAAY,IAC/C,IAAc,mBAAmB,GAAU,IAE3C,IAAe,GAAK,QAAQ,EAAqB,IAEnD,IAAA,QAAS,IAAA;AACV,SAAK,OAAA,KACI,IAAe,EAAa,gBAAgB,GAAA,IAC9C,IAAe,EAAa,cAAc,KAAA,KAExC,GAAA,IACF;AAAA,UAEJ,IACe,AAApB,MAAoB,MACjB,cAAc,GAAU,GAAQ,GAAK,QAAQ,GAAK,QAAQ,GAAW,KACrE,eAAe,GAAU,GAAQ,GAAK,QAAQ,GAAK,QAAQ,GAAW;AAAA,QAExE,aAAa,KAAK,IAAA,EAClB,iBAAiB,KAAA,EAAA,eAAA,GAAA,aAAA,GAAA,OAGX,IAAA,OACA,EAAE,YAAA,YAAA,GAAA,UAAA,GAAA,OAGF;QAAA,KAIJ,OAAO;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;AAAA,QAIR,KAAI,KAAK,OAET,KAAA,CAAA,CAEF,aAAA,IAEA,WAAA;AAAA,aAAA,EAAA,cAEgB,GAAE,cAAA,QACR,KAAK;MAEb,KAAK;AAAA,SAIJ,aAAa,IAAI,IAAI,GACxB,IAAI,SAAA,IAAA;AAAA,UACA,KAAY,aAAA,MAAA,QAAA,qBAAgB;AAAA,aAAA,CACxB,GAAK,IAAI;;OAAA,EAAA,KAAA,uBAAA,OAAA,SAIA,IAAA;AAAA,QACb,KAAqB,KAArB,QAAO,IAAc,KAAd,YACP,IAAW,mBAAmB,GAAS,aAAY,GAAS,QAAQ,GAAG;AAAA,WAAA,iBACtD,EAAS,IAAK,IAAA,QAAiB,EAAS,IAAK,IAAA;OAAA,EAAA,KAAA,cAAA,OAAA,SAG1D,IAAK,IAAE,GAAK,GAAA;AAAA,QAClB,IAAA;AAAA,UACE,IAAQ,KAAK,OAAO;AAAA,UACvB,GAAM;AAAA,kBACE,IAAM,KAAK,oBAAoB,KAAK,MAAM,iBAAiB,OAAA,GAChE,MAAM,OAAO,mBAAmB,GAAO;AAAA,YACxC,IAAQ,UAAU,KAAK,MACvB,IAAI,EAAE,QAAQ,EAAM,OAAO,IAC3B,IAAI,EAAE,QAAQ,EAAM,MAAM,IAC1B,IAAS,MAAK,oBAAoB,KAAK,iBAAiB,SAAS,IAClE,KAAK,iBAAiB,MAAK,KAAK,MAAM,OAAO,OAAM,MAClD,IAAuC,OAA5B,KAAK,MAAM,YAAY,MAAW,KAAK,MAAM,YAAY,QAAQ;AAAA,aAC3E,IAAI,UAAU,GAAG,GAAA,EAAI,MAAM,GAAO,OAAO,IAAU,QAAA,KACnD,IAAI;;AAAA,kBAEC,IAAK,uBAAA,KACV,IAAI,WAAA,GACJ,MAAM,OAAO;;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,SAKd,UAAU,iBAAiB,aAAa,KAAK,YAAA,KAC7C,UAAU,iBAAiB,cAAc,KAAK;OAAA,EAAA,KAAA,aAAA,OAAA,SAG1C,IAAA;AAAA,QACH,KAAS,GAAE,QACb,IAAS,KAAK,WAAW,IAAI,aAAa,OAC1C,IAAY,KAAK,qBACjB,IAAa,KAAK;AAAA,QACnB,EAAO,SAAS,KAAS;AAAA,UACvB,IAAI,EAAO,QAAQ;AAAA,WAClB,WAAW,GAAY,GAAA,QAAU,KACjC,iBAAiB,IAAA,KACjB,sBAAsB,GAAA,KACtB,WAAW,IAAQ,GAAA,MAAS;;AAAA,WAE5B;OAAA,EAAA,KAAA,cAAA,OAAA,WAAA;AAAA,SAKD,WAAW,KAAK,gBAAe,KAAK,qBAAA;SAAoB;EA/IzB;AlBS/B,IkBT+B,mBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,QAAA,IAAA,IAAA,IAAA,MAAA,IAAA,OAAA,IAAA;AAAA,QAAA;AAAA,eAAA,GAAA,IAAA,GAAA,OAAA,aAAA,CAAA,KAAA,KAAA,EAAA,QAAA,SAAA,GAAA,KAAA,EAAA,QAAA,CAAA,KAAA,EAAA,WAAA,IAAA,IAAA;AAAA;aAAA,IAAA;AAAA,UAAA,MAAA,IAAA;cAAA;AAAA,UAAA;AAAA,SAAA,KAAA,EAAA,UAAA,EAAA;gBAAA;AAAA,YAAA;AAAA,gBAAA;;;AAAA,WAAA;;AAAA,SAAA,SAAA,GAAA,GAAA;AAAA,QAAA,MAAA,QAAA;AAAA,aAAA;AAAA,QAAA,OAAA,YAAA,OAAA;AAAA,aAAA,GAAA,GAAA;AAAA,UAAA,IAAA,UAAA;;;AlBS/B,IkBT+B,iBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,aAAA,IAAA,GAAA,IAAA,EAAA,QAAA,KAAA;AAAA,UAAA,IAAA,EAAA;AAAA,QAAA,aAAA,EAAA,cAAA,OAAA,EAAA,eAAA,MAAA,WAAA,KAAA,GAAA,WAAA,OAAA,OAAA,eAAA,IAAA,EAAA,KAAA;;;AAAA,SAAA,SAAA,GAAA,GAAA,GAAA;AAAA,WAAA,KAAA,GAAA,EAAA,WAAA,IAAA,KAAA,GAAA,GAAA,IAAA;;;AlBS/B,ImBTD,YAAY,sBAAsB;AnBSjC,ImBRD,aAAa;AnBQZ,ImBLc,UAAA,SAAA,IAAA;AAAA,aACR,IAAQ,GAAA;AAAA,sBAAA,MAAA;AAAA,QAAA,IAAA,6BAAA,MAAA,GAAA,aAAA,OAAA,eAAA,IAAA,KAAA,MACb,IAAQ;AAAA,MACT,OAAO,WAAA,EAEP,aAAa,EAAQ,cAAc;AAAA,QAEpC,IAAA,CAAe,UAAU,WACzB,IAAiB,EAAY,SAAS,EAAQ,kBAC/C,EAAQ,iBAAiB;AAAA,WAAA,EACvB,sBAAsB,EAAY,QAAQ,IAAA,EAE1C,SAAA;;AAAA,SAAA,YAAA,GAAA,KAAA,eAAA,GAAA,CAAA,EAAA,KAAA,eAAA,OAAA,SAGM,IAAA;AAAA,QACP,KAAI,KAAK;AAAA,SACR,kBAA8C,AAA5B,GAAQ,oBAAoB,IAAI,IAAI,GAAA,GAEzD,SAAS,MAAmB,IAAb,YAAA,GACf,SAAS,SAAS,GAAA,GAClB,eAA4B,IAAb,YAAA,GACf,aAAa,aAAa,qBACzB,eAAe;AAAA,QAEd,IAAI,KAAK,MACT,IAAU,KAAK,kBAAkB,oBAAoB;AAAA,SACpD,mBAAoB,iBAAgB,EAAE,OAAO,EAAE,OACjD,KAAW,YAAY,cAAc;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,QAIpC,KAAU,KAAK,kBAAkB,oBAAoB,GACrD,KAAY,KAAK,MAAM,YAAY,KAAK,MAAM,YAAY;AAAA,SACzD,YAAa,MAAY,MAAW,YACtC,cAAc,KAAK;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,QAGX,KAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAK,KAAK;AAAA,QAClB,GAAK,SAAS,GAAK,OAAO,GAAK,QAAQ,GAAK;AAAA,YACxC,IAAI,MAAM;AAAA,QAGb,GAAK,SAAA,IACH,QAAQ,IAAI,QAAA,GACZ,MAAM,YAAa,GAAK,MAAM,gBAAgB,KAEhD,GAAK,OAAA,IAAY,MAAM,IAAI,SAAA,GAC1B,aAAa,GAAK,cAAA,IAEpB,SAAS,OAAO,KAAK,GAAK,YAAY,MAAM,KAAQ;AAAA,UAClD,KAAA;AAAA,aACG,KAAK,GAAK,YAAY,QAAQ,SAAA,GAAA;AAAA,YAChC,IAAO,IAAI,KAAK,IAAe;AAAA,WAC5B,YAAY,MAAS,GAAK,WAAW;UAAA,GAExC,aAAa;;AAAA,WAGZ;OAAA,EAAA,KAAA,QAAA,OAAA,WAAA;AAAA,QAIH,KAAI,KAAK;AAAA,OAEX,QAAQ,MAAM,KAAK,KAAK,QAAA,GACxB,MAAM,MAAM,KAAK,KAAK,MAAA,GAEtB,iBAAiB,MAAM,GAAE,QAAA,GACzB,YAAY,gBAAgB,GAAE,OAAO,GAAE,MAAA,GACvC,eAAe,iBAChB,OAAO,OAAO,KAAK,KAAK,aAAa,4BAAA,GAEpC,gBAAgB,KAAK;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MAInB,KAAI,KAAK,OACT,IAAU,KAAK,kBAAkB,IAAI,GAErC,IAAmB,GAAE,cAAc,IAAI,SAAC,IAAQ,IAAA;AAAA,aAAA,CACnD,cAAA,EAAA,OAEQ,GAAO,OAAA,UACJ,WAAA,WACC,YAAA,YACC,qBAAA,QACJ,GAAK,aAAa,UAAU,GAAA,YACxB,GAAE,cACZ,OAAO,SAAC,IAAQ,IAAA;AAAA,eAAM,KAAI;SAC1B,IAAI,SAAA,IAAA;AAAA,eAAU,GAAO,KAAK,SAAS;SACnC,OAAO,SAAC,IAAG,IAAA;AAAA,eAAM,KAAI;SAAG,KACvB,aAEJ,WAAA;AAAA,eACQ,GAAE,cAAc;QACtB,KAAK;;AAAA,SAIH,aAAa,IAAI,IAAI,EACxB,IAAI,SAAC,IAAM,IAAA;AAAA,UACP,KAAY,aAAA,MAAA,QAAA,qBAAgB;AAAA,aAAA,CACxB,GAAK,KAAK,MAAM,IAAG;;AAAA,QAIzB,IAAI;AAAA,oBACQ,QAAQ,SAAC,IAAS,IAAA;AAAA,UAAA,CAC7B,GAAG,GAAG,GAAG,SAAS,KAAI;AAAA,YACrB,KAAU,SAAS,kBAAA,CAAmB,YAAU,GAAG,GAAG,IAAA,EAAA,UAE9C,qBAAA,IACN,GAAA,YACQ;AAAA,WAGT,SAAS,YAAY;;AAAA,WAEtB;;OAAA,EAAA,KAAA,UAAA,OAAA,SAIA,IAAA;AACF,UAAA,QACK,MAAM,uBAAA,KAGV,OAAO,KAAK,YAAY,KAAA,KACxB,QAAA,KACA;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,SAIA,UAAU,iBAAiB,aAAa,SAAC,IAAA;AAAA,SACxC,WAAW,QAAQ,SAAA,GAAA;AAAA,YACnB,IAAa,EAAK,OAClB,IAAY,GAAE;AAAA,YACf,EAAW,SAAS,IAAY;AAAA,cAE9B,IAAQ,EAAU,aAAa,eAC/B,IAAY,EAAU,aAAa,aAAa,MAAM,MAEtD,IAAQ,aAAa,SAAS,EAAU,MAAI,GAAA,OAE5C,IAAO,GAAK,UAAU,yBAAyB,IAAO,EAAU,yBAEhE,IAAQ,SAAS,GAAE,OAAO,aAAa,WACvC,IAAI,EAAK,OAAO,EAAK,OAAO,IAAM,GAClC,IAAI,EAAK,MAAM,EAAK,KACpB,IAAQ,IAAQ,MAAM,GAAK,YAC3B,IAAO,SAAS,IAAQ,MAAM,EAAU,KAAK,OAAO,EAAU;AAAA,aAE7D,IAAI,UAAU,GAAG,GAAA,EAAI,MAAM,GAAM,OAAO,GAAO,YAAY,KAAA,KAAA,GAC3D,IAAI;;;;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,SAOP,WAAW,cAAc;AAAA,QAC1B,KAAI,GACJ,IAAI,YACJ,IAAS,KAAK,aAAa,UAAU,GAErC,IAAW,SAAS,kBAAkB,IAAG,GAAG,QAAA,EAAA,UAEpC,sBAAsB,GAAA,IAC5B;AAAA,SAGW,IAAZ,YAAiB,YAAU,GAAA,KAC3B,WAAW,YAAY,IAAA,KAEvB,OAAO,MAAM,GAAG,2BAA2B,IAAI,SAAC,IAAO,IAAA;AAAA,UACrD,IAAS,WAAW,uBAAuB,KAAK,aAAY,KAAK,IACtE,GAAG,qBAAqB,GAAQ;AAAA,SAC5B,WAAW,YAAY;;AAAA,QAIzB,IAAW,SAAS,kBADR,KAAI,4BAA6B,aAAY,KAAK,YAAU,GACvB,GAAG,QAAA,EAAA,UAE5C,sBAAsB,GAAA,IAC5B;AAAA,SAGD,WAAW,YAAY;OAAA,EAAA,KAAA,cAAA,OAAA,WAAA;AAAA,aAIxB,KAAI,KAAK,OAAA,KAAA,CACoB,GAAE,MAAM,YAAY,GAAE,MAAM,gBAAtD,IAAA,GAAA,IAAY,IAAA,GAAA,IAAA,IAAA,CACU,GAAE,IAAI,YAAY,GAAE,IAAI,gBAE/C,IAAA,EAAA,KAAyB,IAAa,IAA6B,KAAA,GAAA,KAAb,IAExD,IAAA,IAEA,IAAe,MAAM,GAAE,QACnB,IAAI,GAAG,IAAI,GAAY,KAAK;AAAA,UAC/B,IAAU,GAAE;AAAA,UAAA,CACZ,eAAe,GAAc,GAAE,MAAM;AAAA,YAAA,IAAA,CACnB,EAAa,YAAY,EAAa;AAAA,YACjD,mBAAA,EAAA,IAAA,EAAA;;AAAA,QAEG,KAAK,KAAK,gBAAgB,GAAc,KAAA,QAE9C,GAAS,IAAA,IACF;;AAAA,WAGT;OAAA,EAAA,KAAA,mBAAA,OAAA,SAGQ,IAAA;AAAA,QAAW,KAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAQ,IAAA,IAAA,CACb,GAAU,YAAY,GAAU,gBAAhD,IAAA,EAAA,IAAO,IAAA,EAAA,IACR,IAAc,eAAe,KAG7B,IAAA,EAAA,OACI,GAAA,MAAA;AAAA,YAAA,KAHE,MAAM,OAAY,mBAAmB,GAAO,IAOrC;AAAA,aACb,IAAiB,gBAAgB,GAAa,KAE9C,IAAA,IAAW,IAAA,QACP,IAAI,GAAG,IAAI,GAAgB;AAAA,UAC5B,KAAK,OAAO,GAAa,IAAA,EAC1B,KAAK,IAAA,QAAA,IAEI,IAAI,KAAK,EAAI,qBAAqB,GAAG,WAC9B;AAAA,WAAA,AAGnB,EAAI,qBAAqB,GAAG,cAHT,UAGS,SACtB,GAAa,IAAA,EAChB,KAAK,KAAK,OAAO,GAAa,GAAA,SAAO,EAG9B,OAAO,GAEb;OAAA,EAAA,KAAA,UAAA,OAAA,SAGD,IAAW,IAAA;AAAA,aAAO,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA,IACpB,IAAI,KAAK,OAGT,IAAc,MAAM,KACpB,IAAA,IAEI,IAAI,GAAG,IAAI,oBAAoB,KAAK,QAAQ,GAAa,IAAI;AAAA,UAChE,IAAA,IAGA,IAAwB,KAAe,EAAE,SAAS,KAAe,EAAE;AAEpE,WAAS,EAAY,eAAe,MAAA,CAAU,IAAA,EACzC,WAAW,YAAY,KAAA,IAErB,KAAK,mBAAmB,IAAA,EAE9B,KAAK;;AAAA,WAGH;OAAA,EAAA,KAAA,sBAAA,OAAA,SAGW,IAAA;AAAA,QACd,KAAW,YAAY,KACvB,IAAY,KAAK,KAAK,WAAW;AAAA,WAAA,EAAA,UAE1B,IAAA,WACC,KAAa,GAAA,MAClB,KAAK,OAAO,iBAAiB,GAAW,KAAK,MAAM;SAAA;EAtRvB;AnBK9B,ImBL8B,iBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,aAAA,IAAA,GAAA,IAAA,EAAA,QAAA,KAAA;AAAA,UAAA,IAAA,EAAA;AAAA,QAAA,aAAA,EAAA,cAAA,OAAA,EAAA,eAAA,MAAA,WAAA,KAAA,GAAA,WAAA,OAAA,OAAA,eAAA,IAAA,EAAA,KAAA;;;AAAA,SAAA,SAAA,GAAA,GAAA,GAAA;AAAA,WAAA,KAAA,GAAA,EAAA,WAAA,IAAA,KAAA,GAAA,GAAA,IAAA;;;AnBK9B,ImBL8B,SAAA,YAAA,GAAA,GAAA,GAAA;AAAA,EAAA,MAAA,QAAA,KAAA,SAAA;AAAA,MAAA,IAAA,OAAA,yBAAA,GAAA;AAAA,MAAA,AAAA,MAAA,QAAA;AAAA,QAAA,IAAA,OAAA,eAAA;AAAA,WAAA,AAAA,MAAA,OAAA,SAAA,GAAA,GAAA,GAAA;;AAAA,MAAA,WAAA;AAAA,WAAA,EAAA;AAAA,MAAA,IAAA,EAAA;AAAA,MAAA,AAAA,MAAA;AAAA,WAAA,EAAA,KAAA;;AnBK9B,IoBPc,YAAA,SAAA,IAAA;AAAA,aACR,IAAQ,GAAA;AAAA,sBAAA,MAAA;AAAA,QAAA,IAAA,6BAAA,MAAA,GAAA,aAAA,OAAA,eAAA,IAAA,KAAA,MACb,IAAQ;AAAA,WAAA,EAET,aAAa,EAAK,cAAA,IAAA,EAClB,cAAc,EAAK,eAAA,IAAA,EAEnB,OAAO,EAAK,QAAQ,QAAA,EACpB,OAAO,GAAA,EAEP,SAAA;;AAAA,SAAA,YAAA,GAAA,KAAA,eAAA,GAAA,CAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAIF,SAAK,KAAK,SAAS,UAAU,KAAA,MAC1B,OAAO,aAAa,GAAA,KACpB,SAAS,SAAS,SAAS;OAAA,EAAA,KAAA,aAAA,OAAA,SAIxB,IAAA;AAAA,WAAA,EAAA,UAAA,aAAA,OAAA,eAAA,EAAA,YAAA,aAAA,MAAA,KAAA,MACO,KAAA,GAER,cAAc,GAAQ,eAAA,IAAA,GACtB,iBAAiB,GAAQ,kBAAA,IAAA,KAE5B,OAAO,YAAY,GAAQ,YAAY,aAAa,QAAA,KACpD,OAAO,YAAY,GAAQ,YAAY,aAAa,QAAA,KACpD,OAAO,YAAY,GAAQ,YAAY,aAAa,GAAA,KACpD,OAAO,sBAAsB,GAAQ,YAAY,uBAAuB,GAAA,KAExE,OAAO,iBAAiB,GAAQ,eAAe,gBAAA,KAC/C,OAAO,iBAAiB,GAAQ,eAAe,gBAAA,KAE/C,OAAO,mBAAmB,GAAQ;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,WAIhC,SAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KADS,KAAK,MACC,KAAK;OAAA,EAAA,KAAA,oBAAA,OAAA,WAAA;AAAA,WAIpB,aAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KADc,KAAK;OAAA,EAAA,KAAA,QAAA,OAAA,WAAA;AAAA,QAItB,KAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,UAAA,UAAA;AAAA,SACC,kBACD,MAAA,KACE,oBAAoB,KAAK,iBAA+B,AAAd,KAAK,SAAS,SAAT,KAEhD;OAAA,EAAA,KAAA,kBAAA,OAAA,WAAA;AAAA,QAID,KAAI,KAAK,OACT,KAAS,KAAK,KAAK;AAAA,OACrB,gBAAgB,GAAO,QAAA,GAEvB,YAAY,KAAK,QAAO,GAAE,eAAA,GAE1B,UAAU,GAAE,YAAU,GAAA,GAMtB,QAAA,EAAA,QACO,IAAA,WACG,GAAO,IAAI,SAAC,IAAG,GAAA;AAAA,aACzB,SAAS,GAAE,UAAU,IAAI,GAAE;;OAAA,EAAA,KAAA,uBAAA,OAAA,SAKV,IAAA;AAAA,QACb,KAAO,mBAAmB,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KADa,UAEvC,IAAkB,KAAK,SAAS,cAAc,KAC9C,IAAiB,gBAAgB,MAAQ,GACzC,IAAW,KAAK,SAAU,aAAa,MAAQ;AAAA,SAEhD,MAAM,QAAA,EAAA,QACF,IAAA,WACG,GAAK,IAAI,SAAA,IAAA;AAAA,aAAK,IAAW,KAAI;QAAA,iBACvB,GAAA,UACP,KAAA,KAIN,qBAAA,KACA,iBAAA,KACA;OAAA,EAAA,KAAA,qBAAA,OAAA,WAAA;AAAA,QAID,KAAI,KAAK,OACT,KAAW,SAAA,IAAA;AAAA,aAAU,GAAO,IAAI,SAAA,IAAA;AAAA,eAAO,MAAM,IAAK,GAAE;;;AAAA,OAEtD,WAAW,KAAK,KAAK,SAAS,IAAI,SAAC,IAAG,GAAA;AAAA,UACnC,IAAS,GAAE,QACX,IAAe,GAAE,gBAAA;AAAA,aAAA,EAAA,MAEd,GAAE,QAAQ,GAAE,KAAK,QAAQ,UAAU,SAAC,KAAA;AAAA,eAAiB,AAAR,OAAQ,MAAM,UAAkB,AAAR,OAAQ,MAAM,SAAS;UAAA,OAC3F,GAAA,WACI,GAAE,WAAA,QAEL,GAAA,YACI,GAAS,IAAA,cAEP,GAAA,gBACE,GAAS;;OAAA,EAAA,KAAA,iBAAA,OAAA,WAAA;AAAA,QAMvB,KAAI,KAAK;AAAA,QACV,KAAK,WAAW;AAAA,aAAA,KAAA,IAChB,YAAY,GAAE,SAAS,GAAE,SAAS,SAAS,GAAG;AAAA,OAG/C,YAAY,IAAI,MAAM,GAAE,eAAe,KAAK,OAAA,GAC5C,SAAS,IAAI,SAAA,IAAA;AAAA,SACZ,WAAW,IAAI,SAAC,IAAK,GAAA;AACnB,aAAM,GAAE,UAAU,MAAA,IAClB,UAAU,KAAK;;;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;AAAA,QAOhB,KAAI,KAAK;AACV,SAAK,KAAK,YAAA,MACP,MAAM,WAAW,KAAK,KAAK,SAAS,IAAI,SAAA,IAAA;AAAA,aAAA,GAC1C,WAAW,MAAM,GAAE,OAAO,GAAE,QAC1B,GAAE,WAAS,IAAE,UAAA,KAIV;SAGN,KAAK,KAAK,YAAA,MACP,MAAM,WAAW,KAAK,KAAK,SAAS,IAAI,SAAA,IAAA;AAAA,aAAA,GAC1C,WAAW,MAAM,GAAE,OAAO,GAAE,QAAA,GAC5B,SAAS,MAAM,GAAE,KAAK,GAAE,QACtB,GAAE,WAAS,IAAE,UAAA,KACV;;OAAA,EAAA,KAAA,iBAAA,OAAA,WAAA;AAAA,QAAA,IAAA,KAAA,MAML,IAAM;AAAA,QAEP,KAAK,WAAW,SAAS;AAAA,UACrB;AAAA,UACF,IAAa,IAAI,MAAM,KAAK,MAAM,eAAe,KAAK;AAAA,WACrD,KAAK,SAAS,IAAI,SAAC,IAAG,IAAA;AAAA,YACtB,IAAS,GAAK,KAAK,SAAS,IAAG;AAAA,WACjC,KAAO,IAAa,EAAW,IAAI,SAAC,KAAG,IAAA;AAAA,iBAAM,MAAI,EAAO;;;;AAAA,QAIxD,IAAgB,KAAK,KAAK,SAAS,IAAI,SAAA,IAAA;AAAA,aAAK,GAAE;;AAAA,WAC/C,KAAK,KAAK,YAAA,EACE,KAAK,KAAK,KAAK,SAAS,IAAI,SAAA,IAAA;AAAA,aAAK,GAAE;SAE/C,KAAK,KAAK,YAAA,KACP,KAAK,SAAS,IAAI,SAAA,IAAA;AAAA,QACR,KAAA,CAAM,GAAE,KAAK,GAAE;QAAA,MAAA,IAIrB,OAAA,MAAA,IAAA,qBAAU;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MAIhB,KAAA,CAAA,CAEF,SAAA,EAAA,MAEO,KAAK,OAAO,WAAA,OACX,KAAK,OAAA,gBACI,KAAK,OAAO,uBAG7B,WAAA;AAAA,aACQ,KAAK,MAAM;MACjB,KAAK,QAAA,CAIP,SAAA,EAAA,MAEO,KAAK,OAAO,WAAA,QACV,KAAK,UAGd,WAAA;AAAA,UACK,KAAI,KAAK;AAAA,aAAA,GACX,MAAM,aAAa,mBAAmB,KAAK,OAC5C,GAAE,MAAM,QAAQ,KAAK,OAAO,YAEtB,GAAE;MACR,KAAK,QAAA,CAIP,YAAA,EAAA,OAEQ,KAAK,OAAA,KACP,WAEN,WAAA;AAAA,aACQ,KAAK,MAAM;MACjB,KAAK,SAIL,IAAc,KAAK,MAAM,SAAS,OAAO,SAAA,IAAA;AAAA,aAAqB,AAAhB,GAAE,cAAc;QAC9D,IAAe,KAAK,MAAM,SAAS,OAAO,SAAA,IAAA;AAAA,aAAqB,AAAhB,GAAE,cAAc;QAE/D,IAAc,EAAY,IAAI,SAAA,IAAA;AAAA,UAC7B,KAAQ,GAAE;AAAA,aAAA,CAEb,cAAmB,GAAE,OAAA,EAAA,OAEb,IAAA,OACA,GAAK,OAAO,KAAA,SACV,GAAK,WAAW,SAAA,kBAGP,GAAK,OAAO,kBAAA,WACnB,GAAK,SAAS,0BAE1B,WAAA;AAAA,YACK,KAAI,KAAK,OACT,KAAI,GAAE,SAAS,KACf,KAAU,KAAK,WAAW,SAE1B,KAAa,KAAK,WAAW,cAAc,uBAC3C,KAAY,GAAE,YAAa,KAAI,KAC/B,KAAW,KAAW,MAAU,IAAI,EAAY,SAEhD,IAAa,GAAE,MAAM,UAAU,IAAI,SAAA,KAAA;AAAA,iBAAK,MAAI,KAAU;;AACtD,cAAA,KACU,EAAW,IAAI,SAAA,KAAA;AAAA,iBAAK,MAAI,KAAW;;AAAA,YAG7C,IAAS,IAAI,MAAM,GAAE,eAAe,KAAK;AAC1C,aAAK,OAAO,oBAAA,KACX,MAAW,GAAE,UAAU,GAAE,SAAS,SAAS,IACpC,GAAE,eAEF,GAAE;AAAA,YAIT,IAAU,IAAI,MAAM,GAAE,eAAe,KAAK;AAAA,eAC3C,MAAA,KACQ,GAAE,WAAW,IAAI,SAAC,KAAG,IAAA;AAAA,iBAAM,MAAI,GAAE,eAAe;aAAA,EAAA,YAI9C,GAAA,YACA,GAAE,YAAA,SACL,GAAA,QAED,GAAA,UAEE,GAAE,MAAM,UAAA,WACP,IAAA,UACD;QAEV,KAAK;QAIL,IAAc,EAAa,IAAI,SAAA,IAAA;AAAA,UAC9B,KAAQ,GAAE;AAAA,aAAA,CAEb,eAAoB,GAAE,OAAA,EAAA,OAEd,IAAA,OACA,GAAK,OAAO,KAAA,SACV,GAAK,SAAA,UACJ,GAAK,YAAY,UAAA,YACf,GAAK,YAAY,YAAA,QACrB,GAAK,YAAY,QAAA,UACf,GAAK,YAAY,UAAA,UACjB,GAAK,YAAY,UAAA,kBAGT,GAAK,OAAO,oBAE/B,WAAA;AAAA,YACK,KAAI,KAAK,OACT,KAAI,GAAE,SAAS,KACf,KAAU,GAAE,MAAM,UAAU,KAAK,GAAE,MAAM,WAC1C,GAAE,MAAM,UAAU,KAAK,GAAE,MAAM;AAAA,eAAA,EAAA,YAGrB,GAAE,MAAM,WAAA,YACR,GAAE,YAAA,QAEN,GAAE,QAAA,UAEA,IAAA,QACF,KAAK,YAAY,WAAW;QAEpC,KAAK;QAIL,IAAA,CAAA,CAEF,YAAA,EAAA,OAEQ,KAAK,OAAA,KACP,WAEN,WAAA;AAAA,aACQ,KAAK,MAAM;MACjB,KAAK;AAAA,SAIU,GAAiB,OAAO,GAAa,GAAa;AAAA,QAEjE,IAAA,CAAa,YAAY;AAAA,SACxB,qBAAA,IAAA,KAEA,aAAa,IAAI,IAAI,GACxB,OAAO,SAAA,IAAA;AAAA,aAAA,CAAS,EAAU,SAAS,GAAK,OAAO,GAAK,MAAM,GAAK;OAC/D,IAAI,SAAA,IAAA;AAAA,UACA,KAAY,aAAA,MAAA,QAAA,qBAAgB;AAAA,aAC7B,IAAK,GAAG,SAAS,gBAAgB,GAAK,GAAG,SAAS,gBAAA,GAC/C,mBAAmB,KAAK,KAAA,CAEtB,GAAK,IAAI;;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,SAKd,cAAA;AAAA,QAED,KAAI,KAAK,OACT,IAAU,KAAK,OAAO,gBACtB,IAAU,KAAK,OAAO;AACb,OAAE,MAAM,OAEd,IAAI,SAAC,GAAO,GAAA;AAAA,UACd,IAAS,GAAK,MAAM,SAAS,IAAI,SAAC,IAAK,IAAA;AAAA,YACtC,KAAQ,GAAI,OAAO;AAAA,eAAA,EAAA,OAEf,GAAI,MAAA,OACJ,IAAA,MACD,GAAI,WAAW,IAAA,OACd,GAAK,OAAO,KAAA,WACR,IAAU,EAAQ,MAAS;;AAAA,SAInC,YAAY,KAAA,EAAA,OACT,GAAA,gBACS,IAAU,EAAQ,KAAS,GAAA,MACrC,GAAE,MAAM,UAAU,IAAA,QAChB,GAAA,UACE,GAAE,UAAU;;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,SAOnB,UAAU,iBAAiB,aAAa,SAAC,IAAA;AAAA,UACzC,IAAI,GAAK,UACT,IAAI,UAAU,GAAK,YACnB,IAAO,GAAE,QAAQ,EAAE,OAAO,cAAc,IACxC,IAAO,GAAE,QAAQ,EAAE;AAEpB,UAAO,GAAK,SAAS,aAAa,MACjC,IAAQ,aAAa,KAAA,GACnB,oBAAoB,KAAA,GAEpB,IAAI;;OAAA,EAAA,KAAA,uBAAA,OAAA,SAKQ,IAAA;AAAA,QACf,KAAI,KAAK;AAAA,QACT,GAAE,WAAA;AAAA,UAEF,IAAQ,kBAAkB,IAAM,GAAE,MAAM,WAAA;AAAW,UACnD,KAAS,GAAG;AAAA,YACX,IAAM,KAAK,YAAY;AAAA,aAEtB,IAAI,UACR,EAAI,OAAO,KAAK,IAAI,OAAO,GAC3B,EAAI,WAAW,KAAK,IAAI,OAAO,GAAA,EAC9B,MAAM,EAAI,gBAAgB,OAAO,MAClC,EAAI,QACJ,IAAA,KAGI,IAAI;;;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;AAAA,QAAA,KAAA,MAKN,KAAI,KAAK;AACV,OAAE,SAAS,SAAS,KAAA,MACjB,WAAW,cAAc,IAAA,GAC5B,SAAS,IAAI,SAAC,IAAG,GAAA;AAAA,UACd,IAAW,sBAGX,IAAO,UAAA,IAEC,GACX,KACA,GACA,GAAK,OAAO,IACZ,GAAE,MACF,GAAK,OAAO;AAAA,SACR,WAAW,YAAY;;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,QAS3B,KAAK;AAAA,aAAA,KAAA,MACF,OAAO;AAGV,SAAK,iBAAA,KACF,cAAc,QAAQ,SAAA,IAAA;AAAA,UACtB,KAAI,GAAE;AAAA,SACR,WAAW,YAAY;QAAA,KAItB,gBAAgB,KAAK,mBAAmB,IAAI,SAAA,IAAA;AAAA,aAAA,EAAA,MAEzC,GAAE,UAAA,SAAA,QACC,OACF,GAAE;QAAA,AAIR,KAAK,MAAM,iBAJH,UAIG,MACR,MAAM,eAAe,KAAK,MAAM,gBAAgB,IAAA,KAIjD,cAAc,IAAI,SAAA,IAAA;AAAA,UAClB,IAAc,GAAE,MAAM,GAAK,MAAM;AAAA,SAEnC,UAAU,YAAY,GAAE,MAAM,IAAA,GAC3B,SAAS,YAAY,GAAE;;OAAA,EAAA,KAAA,uBAAA,OAAA,WAAA;AAK1B,SAAK,iBAAA,KACF,cAAc,QAAQ,SAAA,IAAA;AAAA,UACtB,KAAI,GAAE;AAAA,SACR,WAAW,YAAY;;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,SAMtB,OAAO,iBAAiB,eAAe,WAAA;AAAA,SACtC;;OAAA,EAAA,KAAA,aAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,SAKD,mBAAmB,IAAI,SAAA,IAAA;AAAA,SACzB,MAAM,IAAI,SAAA,IAAA;AAAA,WACN,iBAAiB,SAAS,WAAA;AAAA,cAC1B,IAAQ,GAAK,aAAa;AAAA,aACzB,oBAAoB;;;QAAA,KAMvB,IAAI,UAAU,iBAAiB,SAAS,WAAA;AAAA,UACxC,KAAQ,GAAK,IAAI,UAAU,aAAa;AAAA,SACvC,oBAAoB;;OAAA,EAAA,KAAA,iBAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,SAKrB,cAAc,IAAI,SAAA,IAAA;AAAA,UAClB,IAAc,GAAE,MAAM,GAAK,MAAM;AAAA,oBACvB,GAAE,MAAM,GAAa,GAAE;;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,SAKjC,oBAAoB,KAAK,MAAM,eAAe;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;AAAA,SAI9C,oBAAoB,KAAK,MAAM,eAAe;OAAA,EAAA,KAAA,gBAAA,OAAA,WAAA;AAAA,QAGvC,KAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAM,KAAK,MAAM,cACzB,KAAI,KAAK;AAAA,WAAA,EAAA,OAEL,IAAA,OACA,GAAE,MAAM,OAAO,KAAA,QACd,GAAE,SAAS,IAAI,SAAA,IAAA;AAAA,aAAK,GAAE,OAAO;;OAAA,EAAA,KAAA,uBAAA,OAAA,SAKnB,IAAA;AAAA,QACf,KAAI,KAAK;AAAA,IAAA,MACL,SAAS,OACN,KAAG,MAAQ,IACnB,MAAS,GAAE,MAAM,OAAO,UAAQ,MAAQ,GAAE,MAAM,OAAO,SAAS,IAChE,OAAU,GAAE,gBAAA,IACb,eAAe,IAAA,KACZ,KAAK,QAAQ,eAAe,KAAK;OAAA,EAAA,KAAA,gBAAA,OAAA,SAM1B,IAAO,GAAA;AAAA,QAAe,IAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAM,KAAK,MAAM;AAAA,WAAA,EAAA,UAAA,aAAA,OAAA,eAAA,EAAA,YAAA,gBAAA,MAAA,KAAA,MAChC,IAAO,GAAe,IAAA,KACpC,KAAK,OAAO,OAAO,GAAO,GAAG,KAAA,KAC7B,KAAK,SAAS,IAAI,SAAC,IAAG,IAAA;AAAA,SACxB,OAAO,OAAO,GAAO,GAAG,EAAc;QAAA,KAEpC,OAAO,KAAK;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;AAAA,QAGF,KAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAQ,KAAK,MAAM,gBAAc;AAC5C,SAAK,KAAK,OAAO,UAAU,KAAA,QAAA,EAAA,UAAA,aAAA,OAAA,eAAA,EAAA,YAAA,mBAAA,MAAA,KAAA,MAGT,KAAA,KACjB,KAAK,OAAO,OAAO,IAAO,IAAA,KAC1B,KAAK,SAAS,IAAI,SAAA,IAAA;AAAA,SACpB,OAAO,OAAO,IAAO;QAAA,KAEnB,OAAO,KAAK;OAAA,EAAA,KAAA,iBAAA,OAAA,SAGJ,IAAA;AAAA,QAAe,KAAA,UAAA,SAAA,KAAA,AAAA,UAAA,OAAA,SAAA,UAAA,KAAM;AAAA,SAC7B,KAAK,SAAS,IAAO,SAAS,IAAA,KAC9B,OAAO,KAAK;OAAA,EAAA,KAAA,kBAAA,OAAA,SAKH,IAAA;AAAA,SACT,KAAK,SAAS,IAAI,SAAC,IAAG,GAAA;AACvB,SAAS,MAAA,IACT,SAAS,GAAS;QAAA,KAGjB,OAAO,KAAK;SAAA;EA5jBoB;ApBOhC,IoBPgC,iBAAA,WAAA;AAAA,cAAA,IAAA,GAAA;AAAA,aAAA,IAAA,GAAA,IAAA,EAAA,QAAA,KAAA;AAAA,UAAA,IAAA,EAAA;AAAA,QAAA,aAAA,EAAA,cAAA,OAAA,EAAA,eAAA,MAAA,WAAA,KAAA,GAAA,WAAA,OAAA,OAAA,eAAA,IAAA,EAAA,KAAA;;;AAAA,SAAA,SAAA,GAAA,GAAA,GAAA;AAAA,WAAA,KAAA,GAAA,EAAA,WAAA,IAAA,KAAA,GAAA,GAAA,IAAA;;;ApBOhC,IoBPgC,SAAA,YAAA,GAAA,GAAA,GAAA;AAAA,EAAA,MAAA,QAAA,KAAA,SAAA;AAAA,MAAA,IAAA,OAAA,yBAAA,GAAA;AAAA,MAAA,AAAA,MAAA,QAAA;AAAA,QAAA,IAAA,OAAA,eAAA;AAAA,WAAA,AAAA,MAAA,OAAA,SAAA,GAAA,GAAA,GAAA;;AAAA,MAAA,WAAA;AAAA,WAAA,EAAA;AAAA,MAAA,IAAA,EAAA;AAAA,MAAA,AAAA,MAAA;AAAA,WAAA,EAAA,KAAA;;ApBOhC,IqBTc,aAAA,SAAA,IAAA;AAAA,aACR,IAAQ,GAAA;AAAA,sBAAA,MAAA;AAAA,QAAA,IAAA,6BAAA,MAAA,GAAA,aAAA,OAAA,eAAA,IAAA,KAAA,MACb,IAAQ;AAAA,WAAA,EACT,OAAO,SAAA,EACP,cAAc,GAAA,EACd,OAAO,GAAA,EAEP,SAAA;;AAAA,SAAA,YAAA,GAAA,KAAA,eAAA,GAAA,CAAA,EAAA,KAAA,aAAA,OAAA,SAGI,IAAA;AAAA,WAAA,EAAA,UAAA,aAAA,OAAA,eAAA,EAAA,YAAA,aAAA,MAAA,KAAA,MACO,KAAA,KACX,YAAY,KAAK,UAAU,KAAK,OAAA,KAChC,aAAa,KAAK,WAAW,KAAK,OAAA,KAElC,aAAa,GAAK,cAAc,KAAA,KAChC,OAAO,aAAa,GAAK,cAAc,GAAA,KAEvC,YAAY,GAAK,aAAA,OAAa,KAC9B,cAAc,GAAK,eAAe;OAAA,EAAA,KAAA,QAAA,OAAA,WAAA;AAAA,QAAA,KAAA;AAAA,WAAA,EAAA,UAAA,aAAA,OAAA,eAAA,EAAA,YAAA,QAAA,MAAA,KAAA;AAAA,QAKnC,IAAI,KAAK;AAAA,SACR,SACJ,KAAK,SAAS,KAAK,QAChB,KAAK,OAAO,IAAI,KAAK,cAAc,IACnC,KAAK,OAAO,IAAI,KAAK,cAAc;AAAA,QAE/B,IAAsB,KAAtB,QAAQ,IAAc,KAAd,WAEV,IAAuB,EAAE,oBAAA;AAAA,MAC7B,eAAA,IAAA,EACA,mBAAA;AAAA,QACE,IAAW,MAAM,KAAK,OAAO;AAAA,MAE/B,YAAY,IAAI,SAAC,IAAO,GAAA;AAAA,UACnB,IAAa,GACb,IAAmB,KAAQ,EAAE,aAAc,YAC3C,IAAW,IAAkB,MAAM,IAAG,GACtC,IAAY,IAAA,CAAa,IAAkB,GAC3C,IAAW,KAAsB,GACjC,IAAgB,mBAAmB,GAAY,IAC/C,IAAc,mBAAmB,GAAU,IAE3C,IAAe,GAAK,QAAQ,EAAqB,IAEnD,IAAA,QAAS,IAAA;AACV,SAAK,OAAA,KACI,IAAe,EAAa,gBAAgB,GAAA,IAC9C,IAAe,EAAa,cAAc,KAAA,KAExC,GAAA,IACF;AAAA,UAEJ,IACe,AAApB,MAAoB,MACjB,oBAAoB,GAAU,GAAQ,GAAK,QAAQ,GAAK,QAAQ,GAAK,WAAW,KAChF,qBAAqB,GAAU,GAAQ,GAAK,QAAQ,GAAK,QAAQ,GAAK,WAAW;AAAA,QAEnF,aAAa,KAAK,IAAA,EAClB,iBAAiB,KAAA,EAAA,eAAA,GAAA,aAAA,GAAA,OAGX,IAAA,OACA,EAAE,YAAA,YAAA,GAAA,UAAA,GAAA,OAGF;QAAA,KAIJ,OAAO;OAAA,EAAA,KAAA,mBAAA,OAAA,WAAA;AAAA,QAIR,KAAI,KAAK,OAET,KAAA,CAAA,CAEF,eAAA,IAEA,WAAA;AAAA,aAAA,EAAA,cAEgB,GAAE,cAAA,QACR,KAAK,QAAA,aACA,KAAK;MAElB,KAAK;AAAA,SAIJ,aAAa,IAAI,IAAI,GACxB,IAAI,SAAA,IAAA;AAAA,UACA,KAAY,aAAA,MAAA,QAAA,qBAAgB;AAAA,aAAA,CACxB,GAAK,IAAI;;OAAA,EAAA,KAAA,uBAAA,OAAA,SAIA,IAAA;AAAA,QACZ,KAAuB,KAAvB,QAAQ,IAAe,KAAf,YACT,IAAW,mBAAmB,GAAS,aAAY,GAAS,QAAQ,GAAG;AAAA,WAAA,iBACtD,EAAS,IAAK,IAAA,QAAiB,EAAS,IAAK,IAAA;OAAA,EAAA,KAAA,cAAA,OAAA,SAG1D,IAAK,IAAE,GAAK,GAAA;AAAA,QAClB,IAAA;AAAA,UACE,IAAQ,KAAK,OAAO;AAAA,UACvB,GAAM;AAAA,kBACE,IAAM,KAAK,oBAAoB,KAAK,MAAM,iBAAiB,OAAA,GAChE,MAAM,SAAS,mBAAmB,GAAO;AAAA,YAC1C,IAAQ,UAAU,KAAK,MACvB,IAAI,EAAE,QAAQ,EAAM,OAAO,IAC3B,IAAI,EAAE,QAAQ,EAAM,MAAM,IAC1B,IAAS,MAAK,oBAAoB,KAAK,iBAAiB,SAAS,IAClE,KAAK,iBAAiB,MAAK,KAAK,MAAM,OAAO,OAAM,MAClD,IAAuC,OAA5B,KAAK,MAAM,YAAY,MAAW,KAAK,MAAM,YAAY,QAAQ;AAAA,aAC3E,IAAI,UAAU,GAAG,GAAA,EAAI,MAAM,GAAO,OAAO,IAAU,QAAA,KACnD,IAAI;;AAAA,kBAEC,IAAK,uBAAA,KACV,IAAI,WAAA,GACJ,MAAM,SAAS;;OAAA,EAAA,KAAA,eAAA,OAAA,WAAA;AAAA,SAKhB,UAAU,iBAAiB,aAAa,KAAK,YAAA,KAC7C,UAAU,iBAAiB,cAAc,KAAK;OAAA,EAAA,KAAA,aAAA,OAAA,SAG1C,IAAA;AAAA,QACH,KAAS,GAAE,QACb,IAAS,KAAK,WAAW,IAAI,eAAe,OAC5C,IAAY,KAAK,qBACjB,IAAa,KAAK;AAAA,QACnB,EAAO,SAAS,KAAS;AAAA,UACvB,IAAI,EAAO,QAAQ;AAAA,WAClB,WAAW,GAAY,GAAA,QAAU,KACjC,iBAAiB,IAAA,KACjB,sBAAsB,GAAA,KACtB,WAAW,IAAQ,GAAA,MAAS;;AAAA,WAE5B;OAAA,EAAA,KAAA,cAAA,OAAA,WAAA;AAAA,SAKD,WAAW,KAAK,gBAAe,KAAK,qBAAA;SAAoB;EArJvB;ArBSjC,IYTD,aAAA,EAAA,KACA,WAAA,MACC,WAAA,YAEM,iBAAA,SACH,SAAA,KACJ,UAAA,OACE;AZED,IYeD,QACL,YAAY,GAAQ,GAAA;AAAA,SAAA,gBAAA,MAAA,KACZ,eAAe,EAAQ,MAAM,GAAQ;;", - "names": [] -} diff --git a/node_modules/.vite/neataptic.js b/node_modules/.vite/neataptic.js deleted file mode 100644 index 7755521..0000000 --- a/node_modules/.vite/neataptic.js +++ /dev/null @@ -1,3032 +0,0 @@ -import { - __commonJS, - __esm, - __export -} from "./chunk-ELXAK55F.js"; - -// node_modules/neataptic/src/methods/activation.js -var require_activation = __commonJS({ - "node_modules/neataptic/src/methods/activation.js"(exports, module) { - var activation = { - LOGISTIC: function(x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH: function(x, derivate) { - if (derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY: function(x, derivate) { - return derivate ? 1 : x; - }, - STEP: function(x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function(x, derivate) { - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN: function(x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID: function(x, derivate) { - if (derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN: function(x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR: function(x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function(x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) - return 1 / 2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH: function(x, derivate) { - if (derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function(x, derivate) { - if (derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE: function(x, derivate) { - if (derivate) - return -1; - return 1 - x; - }, - SELU: function(x, derivate) { - var alpha = 1.6732632423543772; - var scale = 1.0507009873554805; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { - return x > 0 ? scale : (fx + alpha) * scale; - } - return fx * scale; - } - }; - module.exports = activation; - } -}); - -// node_modules/neataptic/src/methods/mutation.js -var require_mutation = __commonJS({ - "node_modules/neataptic/src/methods/mutation.js"(exports, module) { - var activation = require_activation(); - var mutation = { - ADD_NODE: { - name: "ADD_NODE" - }, - SUB_NODE: { - name: "SUB_NODE", - keep_gates: true - }, - ADD_CONN: { - name: "ADD_CONN" - }, - SUB_CONN: { - name: "REMOVE_CONN" - }, - MOD_WEIGHT: { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS: { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: "MOD_ACTIVATION", - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN: { - name: "SUB_SELF_CONN" - }, - ADD_GATE: { - name: "ADD_GATE" - }, - SUB_GATE: { - name: "SUB_GATE" - }, - ADD_BACK_CONN: { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN: { - name: "SUB_BACK_CONN" - }, - SWAP_NODES: { - name: "SWAP_NODES", - mutateOutput: true - } - }; - mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES - ]; - mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES - ]; - module.exports = mutation; - } -}); - -// node_modules/neataptic/src/methods/selection.js -var require_selection = __commonJS({ - "node_modules/neataptic/src/methods/selection.js"(exports, module) { - var selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } - }; - module.exports = selection; - } -}); - -// node_modules/neataptic/src/methods/crossover.js -var require_crossover = __commonJS({ - "node_modules/neataptic/src/methods/crossover.js"(exports, module) { - var crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } - }; - module.exports = crossover; - } -}); - -// node_modules/neataptic/src/methods/cost.js -var require_cost = __commonJS({ - "node_modules/neataptic/src/methods/cost.js"(exports, module) { - var cost = { - CROSS_ENTROPY: function(target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error / output.length; - }, - MSE: function(target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - return error / output.length; - }, - BINARY: function(target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - return misses; - }, - MAE: function(target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - return error / output.length; - }, - MAPE: function(target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - return error / output.length; - }, - MSLE: function(target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - return error; - }, - HINGE: function(target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - return error; - } - }; - module.exports = cost; - } -}); - -// node_modules/neataptic/src/methods/gating.js -var require_gating = __commonJS({ - "node_modules/neataptic/src/methods/gating.js"(exports, module) { - var gating = { - OUTPUT: { - name: "OUTPUT" - }, - INPUT: { - name: "INPUT" - }, - SELF: { - name: "SELF" - } - }; - module.exports = gating; - } -}); - -// node_modules/neataptic/src/methods/connection.js -var require_connection = __commonJS({ - "node_modules/neataptic/src/methods/connection.js"(exports, module) { - var connection = { - ALL_TO_ALL: { - name: "OUTPUT" - }, - ALL_TO_ELSE: { - name: "INPUT" - }, - ONE_TO_ONE: { - name: "SELF" - } - }; - module.exports = connection; - } -}); - -// node_modules/neataptic/src/methods/rate.js -var require_rate = __commonJS({ - "node_modules/neataptic/src/methods/rate.js"(exports, module) { - var rate = { - FIXED: function() { - var func = function(baseRate, iteration) { - return baseRate; - }; - return func; - }, - STEP: function(gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - var func = function(baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - return func; - }, - EXP: function(gamma) { - gamma = gamma || 0.999; - var func = function(baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - return func; - }, - INV: function(gamma, power) { - gamma = gamma || 1e-3; - power = power || 2; - var func = function(baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - return func; - } - }; - module.exports = rate; - } -}); - -// node_modules/neataptic/src/methods/methods.js -var require_methods = __commonJS({ - "node_modules/neataptic/src/methods/methods.js"(exports, module) { - var methods = { - activation: require_activation(), - mutation: require_mutation(), - selection: require_selection(), - crossover: require_crossover(), - cost: require_cost(), - gating: require_gating(), - connection: require_connection(), - rate: require_rate() - }; - module.exports = methods; - } -}); - -// node_modules/neataptic/src/architecture/connection.js -var require_connection2 = __commonJS({ - "node_modules/neataptic/src/architecture/connection.js"(exports, module) { - module.exports = Connection; - function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - this.weight = typeof weight === "undefined" ? Math.random() * 0.2 - 0.1 : weight; - this.gater = null; - this.elegibility = 0; - this.previousDeltaWeight = 0; - this.totalDeltaWeight = 0; - this.xtrace = { - nodes: [], - values: [] - }; - } - Connection.prototype = { - toJSON: function() { - var json = { - weight: this.weight - }; - return json; - } - }; - Connection.innovationID = function(a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; - }; - } -}); - -// browser-external:child_process -var child_process_exports = {}; -__export(child_process_exports, { - default: () => child_process_default -}); -var child_process_default; -var init_child_process = __esm({ - "browser-external:child_process"() { - child_process_default = new Proxy({}, { - get() { - throw new Error('Module "child_process" has been externalized for browser compatibility and cannot be accessed in client code.'); - } - }); - } -}); - -// browser-external:path -var path_exports = {}; -__export(path_exports, { - default: () => path_default -}); -var path_default; -var init_path = __esm({ - "browser-external:path"() { - path_default = new Proxy({}, { - get() { - throw new Error('Module "path" has been externalized for browser compatibility and cannot be accessed in client code.'); - } - }); - } -}); - -// node_modules/neataptic/src/multithreading/workers/node/testworker.js -var require_testworker = __commonJS({ - "node_modules/neataptic/src/multithreading/workers/node/testworker.js"(exports, module) { - module.exports = TestWorker; - var cp = (init_child_process(), child_process_exports); - var path = (init_path(), path_exports); - function TestWorker(dataSet, cost) { - this.worker = cp.fork(path.join(__dirname, "/worker")); - this.worker.send({ set: dataSet, cost: cost.name }); - } - TestWorker.prototype = { - evaluate: function(network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - var data = { - activations: serialized[0], - states: serialized[1], - conns: serialized[2] - }; - var _that = this.worker; - this.worker.on("message", function callback(e) { - _that.removeListener("message", callback); - resolve(e); - }); - this.worker.send(data); - }); - }, - terminate: function() { - this.worker.kill(); - } - }; - } -}); - -// node_modules/neataptic/src/multithreading/workers/browser/testworker.js -var require_testworker2 = __commonJS({ - "node_modules/neataptic/src/multithreading/workers/browser/testworker.js"(exports, module) { - module.exports = TestWorker; - var multi = require_multi(); - function TestWorker(dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); - } - TestWorker.prototype = { - evaluate: function(network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - var data = { - activations: new Float64Array(serialized[0]).buffer, - states: new Float64Array(serialized[1]).buffer, - conns: new Float64Array(serialized[2]).buffer - }; - this.worker.onmessage = function(e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - terminate: function() { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - _createBlobString: function(cost) { - var source = ` - var F = [${multi.activations.toString()}]; - var cost = ${cost.toString()}; - var multi = { - deserializeDataSet: ${multi.deserializeDataSet.toString()}, - testSerializedSet: ${multi.testSerializedSet.toString()}, - activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} - }; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - var A = new Float64Array(e.data.activations); - var S = new Float64Array(e.data.states); - var data = new Float64Array(e.data.conns); - - var error = multi.testSerializedSet(set, cost, A, S, data, F); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = multi.deserializeDataSet(new Float64Array(e.data.set)); - } - };`; - return source; - } - }; - } -}); - -// node_modules/neataptic/src/multithreading/workers/workers.js -var require_workers = __commonJS({ - "node_modules/neataptic/src/multithreading/workers/workers.js"(exports, module) { - var workers = { - node: { - TestWorker: require_testworker() - }, - browser: { - TestWorker: require_testworker2() - } - }; - module.exports = workers; - } -}); - -// node_modules/neataptic/src/multithreading/multi.js -var require_multi = __commonJS({ - "node_modules/neataptic/src/multithreading/multi.js"(exports, module) { - var multi = { - workers: require_workers(), - serializeDataSet: function(dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - for (var i2 = 0; i2 < dataSet.length; i2++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i2].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i2].output[j]); - } - } - return serialized; - }, - activateSerializedNetwork: function(input, A, S, data, F) { - for (var i2 = 0; i2 < data[0]; i2++) - A[i2] = input[i2]; - for (i2 = 2; i2 < data.length; i2++) { - let index = data[i2++]; - let bias = data[i2++]; - let squash = data[i2++]; - let selfweight = data[i2++]; - let selfgater = data[i2++]; - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - while (data[i2] !== -2) { - S[index] += A[data[i2++]] * data[i2++] * (data[i2++] === -1 ? 1 : A[data[i2 - 1]]); - } - A[index] = F[squash](S[index]); - } - var output = []; - for (i2 = A.length - data[1]; i2 < A.length; i2++) - output.push(A[i2]); - return output; - }, - deserializeDataSet: function(serializedSet) { - var set = []; - var sampleSize = serializedSet[0] + serializedSet[1]; - for (var i2 = 0; i2 < (serializedSet.length - 2) / sampleSize; i2++) { - let input = []; - for (var j = 2 + i2 * sampleSize; j < 2 + i2 * sampleSize + serializedSet[0]; j++) { - input.push(serializedSet[j]); - } - let output = []; - for (j = 2 + i2 * sampleSize + serializedSet[0]; j < 2 + i2 * sampleSize + sampleSize; j++) { - output.push(serializedSet[j]); - } - set.push(input); - set.push(output); - } - return set; - }, - activations: [ - function(x) { - return 1 / (1 + Math.exp(-x)); - }, - function(x) { - return Math.tanh(x); - }, - function(x) { - return x; - }, - function(x) { - return x > 0 ? 1 : 0; - }, - function(x) { - return x > 0 ? x : 0; - }, - function(x) { - return x / (1 + Math.abs(x)); - }, - function(x) { - return Math.sin(x); - }, - function(x) { - return Math.exp(-Math.pow(x, 2)); - }, - function(x) { - return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; - }, - function(x) { - return x > 0 ? 1 : -1; - }, - function(x) { - return 2 / (1 + Math.exp(-x)) - 1; - }, - function(x) { - return Math.max(-1, Math.min(1, x)); - }, - function(x) { - return Math.abs(x); - }, - function(x) { - return 1 - x; - }, - function(x) { - var a = 1.6732632423543772; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554805; - } - ] - }; - multi.testSerializedSet = function(set, cost, A, S, data, F) { - var error = 0; - for (var i2 = 0; i2 < set.length; i2 += 2) { - let output = multi.activateSerializedNetwork(set[i2], A, S, data, F); - error += cost(set[i2 + 1], output); - } - return error / (set.length / 2); - }; - for (i in multi) { - module.exports[i] = multi[i]; - } - var i; - } -}); - -// node_modules/neataptic/src/config.js -var require_config = __commonJS({ - "node_modules/neataptic/src/config.js"(exports, module) { - var config = { - warnings: false - }; - module.exports = config; - } -}); - -// node_modules/neataptic/src/neat.js -var require_neat = __commonJS({ - "node_modules/neataptic/src/neat.js"(exports, module) { - module.exports = Neat; - var Network = require_network(); - var methods = require_methods(); - var config = require_config(); - var selection = methods.selection; - function Neat(input, output, fitness, options) { - this.input = input; - this.output = output; - this.fitness = fitness; - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - this.fitnessPopulation = options.fitnessPopulation || false; - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - this.template = options.network || false; - this.maxNodes = options.maxNodes || Infinity; - this.maxConns = options.maxConns || Infinity; - this.maxGates = options.maxGates || Infinity; - this.selectMutationMethod = typeof options.mutationSelection === "function" ? options.mutationSelection.bind(this) : this.selectMutationMethod; - this.generation = 0; - this.createPool(this.template); - } - Neat.prototype = { - createPool: function(network) { - this.population = []; - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = void 0; - this.population.push(copy); - } - }, - evolve: async function() { - if (typeof this.population[this.population.length - 1].score === "undefined") { - await this.evaluate(); - } - this.sort(); - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - var newPopulation = []; - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - this.population = newPopulation; - this.mutate(); - this.population.push(...elitists); - for (i = 0; i < this.population.length; i++) { - this.population[i].score = void 0; - } - this.generation++; - return fittest; - }, - getOffspring: function() { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - return Network.crossOver(parent1, parent2, this.equal); - }, - selectMutationMethod: function(genome) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - if (mutationMethod === methods.mutation.ADD_NODE && genome.nodes.length >= this.maxNodes) { - if (config.warnings) - console.warn("maxNodes exceeded!"); - return; - } - if (mutationMethod === methods.mutation.ADD_CONN && genome.connections.length >= this.maxConns) { - if (config.warnings) - console.warn("maxConns exceeded!"); - return; - } - if (mutationMethod === methods.mutation.ADD_GATE && genome.gates.length >= this.maxGates) { - if (config.warnings) - console.warn("maxGates exceeded!"); - return; - } - return mutationMethod; - }, - mutate: function() { - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.selectMutationMethod(this.population[i]); - this.population[i].mutate(mutationMethod); - } - } - } - }, - evaluate: async function() { - var i; - if (this.fitnessPopulation) { - if (this.clear) { - for (i = 0; i < this.population.length; i++) { - this.population[i].clear(); - } - } - await this.fitness(this.population); - } else { - for (i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) - genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - sort: function() { - this.population.sort(function(a, b) { - return b.score - a.score; - }); - }, - getFittest: function() { - if (typeof this.population[this.population.length - 1].score === "undefined") { - this.evaluate(); - } - if (this.population[0].score < this.population[1].score) { - this.sort(); - } - return this.population[0]; - }, - getAverage: function() { - if (typeof this.population[this.population.length - 1].score === "undefined") { - this.evaluate(); - } - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - return score / this.population.length; - }, - getParent: function() { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) - this.sort(); - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - var random = Math.random() * totalFitness; - var value = 0; - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) - return genome; - } - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error("Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size"); - } - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random2 = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random2); - } - individuals.sort(function(a, b) { - return b.score - a.score; - }); - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - export: function() { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - return json; - }, - import: function(json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } - }; - } -}); - -// node_modules/neataptic/src/architecture/node.js -var require_node = __commonJS({ - "node_modules/neataptic/src/architecture/node.js"(exports, module) { - module.exports = Node; - var methods = require_methods(); - var Connection = require_connection2(); - var config = require_config(); - function Node(type) { - this.bias = type === "input" ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || "hidden"; - this.activation = 0; - this.state = 0; - this.old = 0; - this.mask = 1; - this.previousDeltaBias = 0; - this.totalDeltaBias = 0; - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; - } - Node.prototype = { - activate: function(input) { - if (typeof input !== "undefined") { - this.activation = input; - return this.activation; - } - this.old = this.state; - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - var nodes = []; - var influences = []; - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + (node.connections.self.gater === this ? node.old : 0)); - } - conn.gain = this.activation; - } - for (i = 0; i < this.connections.in.length; i++) { - let connection2 = this.connections.in[i]; - connection2.elegibility = this.connections.self.gain * this.connections.self.weight * connection2.elegibility + connection2.from.activation * connection2.gain; - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - let index = connection2.xtrace.nodes.indexOf(node); - if (index > -1) { - connection2.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * connection2.xtrace.values[index] + this.derivative * connection2.elegibility * influence; - } else { - connection2.xtrace.nodes.push(node); - connection2.xtrace.values.push(this.derivative * connection2.elegibility * influence); - } - } - } - return this.activation; - }, - noTraceActivate: function(input) { - if (typeof input !== "undefined") { - this.activation = input; - return this.activation; - } - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - this.activation = this.squash(this.state); - for (i = 0; i < this.connections.gated.length; i++) { - this.connections.gated[i].gain = this.activation; - } - return this.activation; - }, - propagate: function(rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - var error = 0; - if (this.type === "output") { - this.error.responsibility = this.error.projected = target - this.activation; - } else { - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - error += node.error.responsibility * connection.weight * connection.gain; - } - this.error.projected = this.derivative * error; - error = 0; - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - this.error.gated = this.derivative * error; - this.error.responsibility = this.error.projected + this.error.gated; - } - if (this.type === "constant") - return; - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - let gradient = this.error.projected * connection.elegibility; - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - connect: function(target, weight) { - var connections = []; - if (typeof target.bias !== "undefined") { - if (target === this) { - if (this.connections.self.weight !== 0) { - if (config.warnings) - console.warn("This connection already exists!"); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error("Already projecting a connection to this node!"); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - connections.push(connection); - } - } else { - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - connections.push(connection); - } - } - return connections; - }, - disconnect: function(node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) - conn.gater.ungate(conn); - break; - } - } - if (twosided) { - node.disconnect(this); - } - }, - gate: function(connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - this.connections.gated.push(connection); - connection.gater = this; - } - }, - ungate: function(connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - clear: function() { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - mutate: function(method) { - if (typeof method === "undefined") { - throw new Error("No mutate method given!"); - } else if (!(method.name in methods.mutation)) { - throw new Error("This method does not exist!"); - } - switch (method) { - case methods.mutation.MOD_ACTIVATION: - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - isProjectingTo: function(node) { - if (node === this && this.connections.self.weight !== 0) - return true; - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - return false; - }, - isProjectedBy: function(node) { - if (node === this && this.connections.self.weight !== 0) - return true; - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - return false; - }, - toJSON: function() { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - return json; - } - }; - Node.fromJSON = function(json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - node.squash = methods.activation[json.squash]; - return node; - }; - } -}); - -// browser-external:os -var os_exports = {}; -__export(os_exports, { - default: () => os_default -}); -var os_default; -var init_os = __esm({ - "browser-external:os"() { - os_default = new Proxy({}, { - get() { - throw new Error('Module "os" has been externalized for browser compatibility and cannot be accessed in client code.'); - } - }); - } -}); - -// node_modules/neataptic/src/architecture/network.js -var require_network = __commonJS({ - "node_modules/neataptic/src/architecture/network.js"(exports, module) { - module.exports = Network; - var multi = require_multi(); - var methods = require_methods(); - var Connection = require_connection2(); - var config = require_config(); - var Neat = require_neat(); - var Node = require_node(); - var mutation = methods.mutation; - function Network(input, output) { - if (typeof input === "undefined" || typeof output === "undefined") { - throw new Error("No input or output size given"); - } - this.input = input; - this.output = output; - this.nodes = []; - this.connections = []; - this.gates = []; - this.selfconns = []; - this.dropout = 0; - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = i < this.input ? "input" : "output"; - this.nodes.push(new Node(type)); - } - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } - } - Network.prototype = { - activate: function(input, training) { - var output = []; - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === "input") { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === "output") { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) - this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - noTraceActivate: function(input) { - var output = []; - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === "input") { - this.nodes[i].noTraceActivate(input[i]); - } else if (this.nodes[i].type === "output") { - var activation = this.nodes[i].noTraceActivate(); - output.push(activation); - } else { - this.nodes[i].noTraceActivate(); - } - } - return output; - }, - propagate: function(rate, momentum, update, target) { - if (typeof target === "undefined" || target.length !== this.output) { - throw new Error("Output target length should match network output length"); - } - var targetIndex = target.length; - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - clear: function() { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - connect: function(from, to, weight) { - var connections = from.connect(to, weight); - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - return connections; - }, - disconnect: function(from, to) { - var connections = from === to ? this.selfconns : this.connections; - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) - this.ungate(connection); - connections.splice(i, 1); - break; - } - } - from.disconnect(to); - }, - gate: function(node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error("This node is not part of the network!"); - } else if (connection.gater != null) { - if (config.warnings) - console.warn("This connection is already gated!"); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - ungate: function(connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error("This connection is not gated!"); - } - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - remove: function(node) { - var index = this.nodes.indexOf(node); - if (index === -1) { - throw new Error("This node does not exist in the network!"); - } - var gaters = []; - this.disconnect(node, node); - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) - break; - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn2 = node.connections.gated[i]; - this.ungate(conn2); - } - this.disconnect(node, node); - this.nodes.splice(index, 1); - }, - mutate: function(method) { - if (typeof method === "undefined") { - throw new Error("No (correct) mutate method given!"); - } - var i, j; - switch (method) { - case mutation.ADD_NODE: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node("hidden"); - node.mutate(mutation.MOD_ACTIVATION); - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - if (this.nodes.length === this.input + this.output) { - if (config.warnings) - console.warn("No more nodes left to remove!"); - break; - } - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node12 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node22 = this.nodes[j]; - if (!node12.isProjectingTo(node22)) - available.push([node12, node22]); - } - } - if (available.length === 0) { - if (config.warnings) - console.warn("No more connections to be made!"); - break; - } - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - var possible = []; - for (i = 0; i < this.connections.length; i++) { - let conn2 = this.connections[i]; - if (conn2.from.connections.out.length > 1 && conn2.to.connections.in.length > 1 && this.nodes.indexOf(conn2.to) > this.nodes.indexOf(conn2.from)) { - possible.push(conn2); - } - } - if (possible.length === 0) { - if (config.warnings) - console.warn("No connections to remove!"); - break; - } - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var allconnections = this.connections.concat(this.selfconns); - var connection = allconnections[Math.floor(Math.random() * allconnections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) - console.warn("No nodes that allow mutation of activation function"); - break; - } - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node3 = this.nodes[i]; - if (node3.connections.self.weight === 0) { - possible.push(node3); - } - } - if (possible.length === 0) { - if (config.warnings) - console.warn("No more self-connections to add!"); - break; - } - var node = possible[Math.floor(Math.random() * possible.length)]; - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) - console.warn("No more self-connections to remove!"); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn2 = allconnections[i]; - if (conn2.gater === null) { - possible.push(conn2); - } - } - if (possible.length === 0) { - if (config.warnings) - console.warn("No more connections to gate!"); - break; - } - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - this.gate(node, conn); - break; - case mutation.SUB_GATE: - if (this.gates.length === 0) { - if (config.warnings) - console.warn("No more connections to ungate!"); - break; - } - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node12 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node22 = this.nodes[j]; - if (!node12.isProjectingTo(node22)) - available.push([node12, node22]); - } - } - if (available.length === 0) { - if (config.warnings) - console.warn("No more connections to be made!"); - break; - } - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - var possible = []; - for (i = 0; i < this.connections.length; i++) { - let conn2 = this.connections[i]; - if (conn2.from.connections.out.length > 1 && conn2.to.connections.in.length > 1 && this.nodes.indexOf(conn2.from) > this.nodes.indexOf(conn2.to)) { - possible.push(conn2); - } - } - if (possible.length === 0) { - if (config.warnings) - console.warn("No connections to remove!"); - break; - } - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - if (method.mutateOutput && this.nodes.length - this.input < 2 || !method.mutateOutput && this.nodes.length - this.input - this.output < 2) { - if (config.warnings) - console.warn("No nodes that allow swapping of bias and activation function"); - break; - } - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - var biasTemp = node1.bias; - var squashTemp = node1.squash; - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - train: function(set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error("Dataset input/output size should be same as network input/output size!"); - } - options = options || {}; - if (typeof options.rate === "undefined") { - if (config.warnings) - console.warn("Using default learning rate, please define a rate!"); - } - if (typeof options.iterations === "undefined") { - if (config.warnings) - console.warn("No target iterations given, running until error is reached!"); - } - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - var start = Date.now(); - if (batchSize > set.length) { - throw new Error("Batch size must be smaller or equal to dataset length!"); - } else if (typeof options.iterations === "undefined" && typeof options.error === "undefined") { - throw new Error("At least one of the following options must be specified: error, iterations"); - } else if (typeof options.error === "undefined") { - targetError = -1; - } else if (typeof options.iterations === "undefined") { - options.iterations = 0; - } - this.dropout = dropout; - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - var currentRate = baseRate; - var iteration = 0; - var error = 1; - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) - break; - iteration++; - currentRate = ratePolicy(baseRate, iteration); - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) - this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) - this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) - this.clear(); - } - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x) - ; - } - if (options.log && iteration % options.log === 0) { - console.log("iteration", iteration, "error", error, "rate", currentRate); - } - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error, iteration }); - } - } - if (options.clear) - this.clear(); - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === "hidden" || this.nodes[i].type === "constant") { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - return { - error, - iterations: iteration, - time: Date.now() - start - }; - }, - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - var update = !!((i + 1) % batchSize === 0 || i + 1 === set.length); - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - test: function(set, cost = methods.cost.MSE) { - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === "hidden" || this.nodes[i].type === "constant") { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - var error = 0; - var start = Date.now(); - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.noTraceActivate(input); - error += cost(target, output); - } - error /= set.length; - var results = { - error, - time: Date.now() - start - }; - return results; - }, - graph: function(width, height) { - var input = 0; - var output = 0; - var json = { - nodes: [], - links: [], - constraints: [{ - type: "alignment", - axis: "x", - offsets: [] - }, { - type: "alignment", - axis: "y", - offsets: [] - }] - }; - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - if (node.type === "input") { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === "output") { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - json.nodes.push({ - id: i, - name: node.type === "hidden" ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: "GATE" - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - return json; - }, - toJSON: function() { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - if (node.connections.self.weight !== 0) { - let tojson2 = node.connections.self.toJSON(); - tojson2.from = i; - tojson2.to = i; - tojson2.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson2); - } - } - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - tojson.gater = conn.gater != null ? conn.gater.index : null; - json.connections.push(tojson); - } - return json; - }, - set: function(values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - evolve: async function(set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error("Dataset input/output size should be same as network input/output size!"); - } - options = options || {}; - var targetError = typeof options.error !== "undefined" ? options.error : 0.05; - var growth = typeof options.growth !== "undefined" ? options.growth : 1e-4; - var cost = options.cost || methods.cost.MSE; - var amount = options.amount || 1; - var threads = options.threads; - if (typeof threads === "undefined") { - if (typeof window === "undefined") { - threads = (init_os(), os_exports).cpus().length; - } else { - threads = navigator.hardwareConcurrency; - } - } - var start = Date.now(); - if (typeof options.iterations === "undefined" && typeof options.error === "undefined") { - throw new Error("At least one of the following options must be specified: error, iterations"); - } else if (typeof options.error === "undefined") { - targetError = -1; - } else if (typeof options.iterations === "undefined") { - options.iterations = 0; - } - var fitnessFunction; - if (threads === 1) { - fitnessFunction = function(genome) { - var score = 0; - for (var i2 = 0; i2 < amount; i2++) { - score -= genome.test(set, cost).error; - } - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; - return score / amount; - }; - } else { - var converted = multi.serializeDataSet(set); - var workers = []; - if (typeof window === "undefined") { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.node.TestWorker(converted, cost)); - } - } else { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.browser.TestWorker(converted, cost)); - } - } - fitnessFunction = function(population) { - return new Promise((resolve, reject) => { - var queue = population.slice(); - var done = 0; - var startWorker = function(worker) { - if (!queue.length) { - if (++done === threads) - resolve(); - return; - } - var genome = queue.shift(); - worker.evaluate(genome).then(function(result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(parseFloat(result)) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - for (var i2 = 0; i2 < workers.length; i2++) { - startWorker(workers[i2]); - } - }); - }; - options.fitnessPopulation = true; - } - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - if (options.log && neat.generation % options.log === 0) { - console.log("iteration", neat.generation, "fitness", fitness, "error", -error); - } - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness, error: -error, iteration: neat.generation }); - } - } - if (threads > 1) { - for (var i = 0; i < workers.length; i++) - workers[i].terminate(); - } - if (typeof bestGenome !== "undefined") { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.selfconns = bestGenome.selfconns; - this.gates = bestGenome.gates; - if (options.clear) - this.clear(); - } - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - standalone: function() { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - lines.push("for(var i = 0; i < input.length; i++) A[i] = input[i];"); - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - for (i = this.input; i < this.nodes.length; i++) { - let node2 = this.nodes[i]; - activations.push(node2.activation); - states.push(node2.state); - var functionIndex = present.indexOf(node2.squash.name); - if (functionIndex === -1) { - functionIndex = present.length; - present.push(node2.squash.name); - functions.push(node2.squash.toString()); - } - var incoming = []; - for (var j = 0; j < node2.connections.in.length; j++) { - var conn = node2.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - incoming.push(computation); - } - if (node2.connections.self.weight) { - let conn2 = node2.connections.self; - let computation2 = `S[${i}] * ${conn2.weight}`; - if (conn2.gater != null) { - computation2 += ` * A[${conn2.gater.index}]`; - } - incoming.push(computation2); - } - var line1 = `S[${i}] = ${incoming.join(" + ")} + ${node2.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node2.mask ? " * " + node2.mask : ""};`; - lines.push(line1); - lines.push(line2); - } - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - output = `return [${output.join(",")}];`; - lines.push(output); - var total = ""; - total += `var F = [${functions.toString()}];\r -`; - total += `var A = [${activations.toString()}];\r -`; - total += `var S = [${states.toString()}];\r -`; - total += `function activate(input){\r -${lines.join("\r\n")}\r -}`; - return total; - }, - serialize: function() { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - "LOGISTIC", - "TANH", - "IDENTITY", - "STEP", - "RELU", - "SOFTSIGN", - "SINUSOID", - "GAUSSIAN", - "BENT_IDENTITY", - "BIPOLAR", - "BIPOLAR_SIGMOID", - "HARD_TANH", - "ABSOLUTE", - "INVERSE", - "SELU" - ]; - conns.push(this.input); - conns.push(this.output); - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - conns.push(-2); - } - return [activations, states, conns]; - } - }; - Network.fromJSON = function(json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - return network; - }; - Network.merge = function(network1, network2) { - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - if (network1.output !== network2.input) { - throw new Error("Output size of network1 should be the same as the input size of network2!"); - } - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === "input") { - let index = network2.nodes.indexOf(conn.from); - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = "hidden"; - } - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - return network1; - }; - Network.crossOver = function(network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - var score1 = network1.score || 0; - var score2 = network2.score || 0; - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - var outputSize = network1.output; - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - for (i = 0; i < size; i++) { - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - if (typeof node === "undefined" || node.type === "output") { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - offspring.nodes.push(newNode); - } - var n1conns = {}; - var n2conns = {}; - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - if (typeof n2conns[keys1[i]] !== "undefined") { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - n2conns[keys1[i]] = void 0; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== "undefined") { - connections.push(n2conns[keys2[i]]); - } - } - } - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - conn.weight = connData.weight; - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - }; - } -}); - -// node_modules/neataptic/src/architecture/layer.js -var require_layer = __commonJS({ - "node_modules/neataptic/src/architecture/layer.js"(exports, module) { - module.exports = Layer; - var methods = require_methods(); - var Group = require_group(); - var Node = require_node(); - function Layer() { - this.output = null; - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - } - Layer.prototype = { - activate: function(value) { - var values = []; - if (typeof value !== "undefined" && value.length !== this.nodes.length) { - throw new Error("Array with values should be same as the amount of nodes!"); - } - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === "undefined") { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - values.push(activation); - } - return values; - }, - propagate: function(rate, momentum, target) { - if (typeof target !== "undefined" && target.length !== this.nodes.length) { - throw new Error("Array with values should be same as the amount of nodes!"); - } - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === "undefined") { - this.nodes[i].propagate(rate, momentum, true); - } else { - this.nodes[i].propagate(rate, momentum, true, target[i]); - } - } - }, - connect: function(target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - return connections; - }, - gate: function(connections, method) { - this.output.gate(connections, method); - }, - set: function(values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - if (node instanceof Node) { - if (typeof values.bias !== "undefined") { - node.bias = values.bias; - } - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - disconnect: function(target, twosided) { - twosided = twosided || false; - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - clear: function() { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } - }; - Layer.Dense = function(size) { - var layer = new Layer(); - var block = new Group(size); - layer.nodes.push(block); - layer.output = block; - layer.input = function(from, method, weight) { - if (from instanceof Layer) - from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - return layer; - }; - Layer.LSTM = function(size) { - var layer = new Layer(); - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - layer.output = outputBlock; - layer.input = function(from, method, weight) { - if (from instanceof Layer) - from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - inputGate.gate(input, methods.gating.INPUT); - return connections; - }; - return layer; - }; - Layer.GRU = function(size) { - var layer = new Layer(); - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: "constant" - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: "constant" - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - resetGate.gate(reset, methods.gating.OUTPUT); - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - layer.output = output; - layer.input = function(from, method, weight) { - if (from instanceof Layer) - from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - return connections; - }; - return layer; - }; - Layer.Memory = function(size, memory) { - var layer = new Layer(); - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: "constant" - }); - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - layer.nodes.push(block); - previous = block; - } - layer.nodes.reverse(); - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - layer.input = function(from, method, weight) { - if (from instanceof Layer) - from = from.output; - method = method || methods.connection.ALL_TO_ALL; - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error("Previous layer size must be same as memory size"); - } - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - return layer; - }; - } -}); - -// node_modules/neataptic/src/architecture/group.js -var require_group = __commonJS({ - "node_modules/neataptic/src/architecture/group.js"(exports, module) { - module.exports = Group; - var methods = require_methods(); - var config = require_config(); - var Layer = require_layer(); - var Node = require_node(); - function Group(size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } - } - Group.prototype = { - activate: function(value) { - var values = []; - if (typeof value !== "undefined" && value.length !== this.nodes.length) { - throw new Error("Array with values should be same as the amount of nodes!"); - } - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === "undefined") { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - values.push(activation); - } - return values; - }, - propagate: function(rate, momentum, target) { - if (typeof target !== "undefined" && target.length !== this.nodes.length) { - throw new Error("Array with values should be same as the amount of nodes!"); - } - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === "undefined") { - this.nodes[i].propagate(rate, momentum, true); - } else { - this.nodes[i].propagate(rate, momentum, true, target[i]); - } - } - }, - connect: function(target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === "undefined") { - if (this !== target) { - if (config.warnings) - console.warn("No group connection specified, using ALL_TO_ALL"); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) - console.warn("No group connection specified, using ONE_TO_ONE"); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) - continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error("From and To group must be the same size!"); - } - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - return connections; - }, - gate: function(connections, method) { - if (typeof method === "undefined") { - throw new Error("Please specify Gating.INPUT, Gating.OUTPUT"); - } - if (!Array.isArray(connections)) { - connections = [connections]; - } - var nodes1 = []; - var nodes2 = []; - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) - nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) - nodes2.push(connection.to); - } - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - set: function(values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== "undefined") { - this.nodes[i].bias = values.bias; - } - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - disconnect: function(target, twosided) { - twosided = twosided || false; - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn2 = this.connections.out[k]; - if (conn2.from === this.nodes[i] && conn2.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn2 = this.connections.in[k]; - if (conn2.from === target.nodes[j] && conn2.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn2 = this.connections.out[j]; - if (conn2.from === this.nodes[i] && conn2.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - clear: function() { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } - }; - } -}); - -// node_modules/neataptic/src/architecture/architect.js -var require_architect = __commonJS({ - "node_modules/neataptic/src/architecture/architect.js"(exports, module) { - var methods = require_methods(); - var Network = require_network(); - var Group = require_group(); - var Layer = require_layer(); - var Node = require_node(); - var architect = { - Construct: function(list) { - var network = new Network(0, 0); - var nodes = []; - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === "output" || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = "output"; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === "input" || !nodes[i].connections.in.length) { - nodes[i].type = "input"; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - nodes = inputs.concat(nodes).concat(outputs); - if (network.input === 0 || network.output === 0) { - throw new Error("Given nodes have no clear input/output node!"); - } - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - network.nodes = nodes; - return network; - }, - Perceptron: function() { - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error("You have to specify at least 3 layers"); - } - var nodes = []; - nodes.push(new Group(layers[0])); - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - return architect.Construct(nodes); - }, - Random: function(input, hidden, output, options) { - options = options || {}; - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - var network = new Network(input, output); - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - return network; - }, - LSTM: function() { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error("You have to specify at least 3 layers"); - } - var last = args.pop(); - var outputLayer; - if (typeof last === "number") { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); - } - outputLayer.set({ - type: "output" - }); - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === void 0 ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === void 0 ? true : last.inputToDeep; - var inputLayer = new Group(args.shift()); - inputLayer.set({ - type: "input" - }); - var blocks = args; - var nodes = []; - nodes.push(inputLayer); - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - if (options.inputToDeep && i > 0) { - let input2 = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input2, methods.gating.INPUT); - } - if (options.memoryToMemory) { - let input2 = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input2, methods.gating.INPUT); - } - if (options.outputToMemory) { - let input2 = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input2, methods.gating.INPUT); - } - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) - nodes.push(outputBlock); - previous = outputBlock; - } - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - GRU: function() { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error("not enough layers (minimum 3) !!"); - } - var inputLayer = new Group(args.shift()); - var outputLayer = new Group(args.pop()); - var blocks = args; - var nodes = []; - nodes.push(inputLayer); - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - nodes.push(layer); - } - previous.connect(outputLayer); - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - Hopfield: function(size) { - var input = new Group(size); - var output = new Group(size); - input.connect(output, methods.connection.ALL_TO_ALL); - input.set({ - type: "input" - }); - output.set({ - squash: methods.activation.STEP, - type: "output" - }); - var network = new architect.Construct([input, output]); - return network; - }, - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - var nodes = []; - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - nodes.push(input); - nodes.push(outputMemory); - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== "undefined") { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - nodes.push(inputMemory); - nodes.push(output); - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.set({ - type: "input" - }); - output.set({ - type: "output" - }); - return architect.Construct(nodes); - } - }; - module.exports = architect; - } -}); - -// node_modules/neataptic/src/neataptic.js -var require_neataptic = __commonJS({ - "node_modules/neataptic/src/neataptic.js"(exports, module) { - var Neataptic = { - methods: require_methods(), - Connection: require_connection2(), - architect: require_architect(), - Network: require_network(), - config: require_config(), - Group: require_group(), - Layer: require_layer(), - Node: require_node(), - Neat: require_neat(), - multi: require_multi() - }; - if (typeof define !== "undefined" && define.amd) { - define([], function() { - return Neataptic; - }); - } - if (typeof module !== "undefined" && module.exports) { - module.exports = Neataptic; - } - if (typeof window === "object") { - (function() { - var old = window["neataptic"]; - Neataptic.ninja = function() { - window["neataptic"] = old; - return Neataptic; - }; - })(); - window["neataptic"] = Neataptic; - } - } -}); - -// dep:neataptic -var neataptic_default = require_neataptic(); -export { - neataptic_default as default -}; -//# sourceMappingURL=neataptic.js.map diff --git a/node_modules/.vite/neataptic.js.map b/node_modules/.vite/neataptic.js.map deleted file mode 100644 index 64f7adb..0000000 --- a/node_modules/.vite/neataptic.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../neataptic/src/methods/activation.js", "../neataptic/src/methods/mutation.js", "../neataptic/src/methods/selection.js", "../neataptic/src/methods/crossover.js", "../neataptic/src/methods/cost.js", "../neataptic/src/methods/gating.js", "../neataptic/src/methods/connection.js", "../neataptic/src/methods/rate.js", "../neataptic/src/methods/methods.js", "../neataptic/src/architecture/connection.js", "browser-external:child_process", "browser-external:path", "../neataptic/src/multithreading/workers/node/testworker.js", "../neataptic/src/multithreading/workers/browser/testworker.js", "../neataptic/src/multithreading/workers/workers.js", "../neataptic/src/multithreading/multi.js", "../neataptic/src/config.js", "../neataptic/src/neat.js", "../neataptic/src/architecture/node.js", "browser-external:os", "../neataptic/src/architecture/network.js", "../neataptic/src/architecture/layer.js", "../neataptic/src/architecture/group.js", "../neataptic/src/architecture/architect.js", "../neataptic/src/neataptic.js", "dep:neataptic"], - "sourcesContent": ["/*******************************************************************************\r\n ACTIVATION FUNCTIONS\r\n*******************************************************************************/\r\n\r\n// https://en.wikipedia.org/wiki/Activation_function\r\n// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons\r\nvar activation = {\r\n LOGISTIC: function (x, derivate) {\r\n var fx = 1 / (1 + Math.exp(-x));\r\n if (!derivate) return fx;\r\n return fx * (1 - fx);\r\n },\r\n TANH: function (x, derivate) {\r\n if (derivate) return 1 - Math.pow(Math.tanh(x), 2);\r\n return Math.tanh(x);\r\n },\r\n IDENTITY: function (x, derivate) {\r\n return derivate ? 1 : x;\r\n },\r\n STEP: function (x, derivate) {\r\n return derivate ? 0 : x > 0 ? 1 : 0;\r\n },\r\n RELU: function (x, derivate) {\r\n if (derivate) return x > 0 ? 1 : 0;\r\n return x > 0 ? x : 0;\r\n },\r\n SOFTSIGN: function (x, derivate) {\r\n var d = 1 + Math.abs(x);\r\n if (derivate) return x / Math.pow(d, 2);\r\n return x / d;\r\n },\r\n SINUSOID: function (x, derivate) {\r\n if (derivate) return Math.cos(x);\r\n return Math.sin(x);\r\n },\r\n GAUSSIAN: function (x, derivate) {\r\n var d = Math.exp(-Math.pow(x, 2));\r\n if (derivate) return -2 * x * d;\r\n return d;\r\n },\r\n BENT_IDENTITY: function (x, derivate) {\r\n var d = Math.sqrt(Math.pow(x, 2) + 1);\r\n if (derivate) return x / (2 * d) + 1;\r\n return (d - 1) / 2 + x;\r\n },\r\n BIPOLAR: function (x, derivate) {\r\n return derivate ? 0 : x > 0 ? 1 : -1;\r\n },\r\n BIPOLAR_SIGMOID: function (x, derivate) {\r\n var d = 2 / (1 + Math.exp(-x)) - 1;\r\n if (derivate) return 1 / 2 * (1 + d) * (1 - d);\r\n return d;\r\n },\r\n HARD_TANH: function (x, derivate) {\r\n if (derivate) return x > -1 && x < 1 ? 1 : 0;\r\n return Math.max(-1, Math.min(1, x));\r\n },\r\n ABSOLUTE: function (x, derivate) {\r\n if (derivate) return x < 0 ? -1 : 1;\r\n return Math.abs(x);\r\n },\r\n INVERSE: function (x, derivate) {\r\n if (derivate) return -1;\r\n return 1 - x;\r\n },\r\n // https://arxiv.org/pdf/1706.02515.pdf\r\n SELU: function (x, derivate) {\r\n var alpha = 1.6732632423543772848170429916717;\r\n var scale = 1.0507009873554804934193349852946;\r\n var fx = x > 0 ? x : alpha * Math.exp(x) - alpha;\r\n if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; }\r\n return fx * scale;\r\n }\r\n};\r\n\r\n/* Export */\r\nmodule.exports = activation;\r\n", "/* Import */\r\nvar activation = require('./activation');\r\n\r\n/*******************************************************************************\r\n MUTATION\r\n*******************************************************************************/\r\n\r\n// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm)\r\nvar mutation = {\r\n ADD_NODE: {\r\n name: 'ADD_NODE'\r\n },\r\n SUB_NODE: {\r\n name: 'SUB_NODE',\r\n keep_gates: true\r\n },\r\n ADD_CONN: {\r\n name: 'ADD_CONN'\r\n },\r\n SUB_CONN: {\r\n name: 'REMOVE_CONN'\r\n },\r\n MOD_WEIGHT: {\r\n name: 'MOD_WEIGHT',\r\n min: -1,\r\n max: 1\r\n },\r\n MOD_BIAS: {\r\n name: 'MOD_BIAS',\r\n min: -1,\r\n max: 1\r\n },\r\n MOD_ACTIVATION: {\r\n name: 'MOD_ACTIVATION',\r\n mutateOutput: true,\r\n allowed: [\r\n activation.LOGISTIC,\r\n activation.TANH,\r\n activation.RELU,\r\n activation.IDENTITY,\r\n activation.STEP,\r\n activation.SOFTSIGN,\r\n activation.SINUSOID,\r\n activation.GAUSSIAN,\r\n activation.BENT_IDENTITY,\r\n activation.BIPOLAR,\r\n activation.BIPOLAR_SIGMOID,\r\n activation.HARD_TANH,\r\n activation.ABSOLUTE,\r\n activation.INVERSE,\r\n activation.SELU\r\n ]\r\n },\r\n ADD_SELF_CONN: {\r\n name: 'ADD_SELF_CONN'\r\n },\r\n SUB_SELF_CONN: {\r\n name: 'SUB_SELF_CONN'\r\n },\r\n ADD_GATE: {\r\n name: 'ADD_GATE'\r\n },\r\n SUB_GATE: {\r\n name: 'SUB_GATE'\r\n },\r\n ADD_BACK_CONN: {\r\n name: 'ADD_BACK_CONN'\r\n },\r\n SUB_BACK_CONN: {\r\n name: 'SUB_BACK_CONN'\r\n },\r\n SWAP_NODES: {\r\n name: 'SWAP_NODES',\r\n mutateOutput: true\r\n }\r\n};\r\n\r\nmutation.ALL = [\r\n mutation.ADD_NODE,\r\n mutation.SUB_NODE,\r\n mutation.ADD_CONN,\r\n mutation.SUB_CONN,\r\n mutation.MOD_WEIGHT,\r\n mutation.MOD_BIAS,\r\n mutation.MOD_ACTIVATION,\r\n mutation.ADD_GATE,\r\n mutation.SUB_GATE,\r\n mutation.ADD_SELF_CONN,\r\n mutation.SUB_SELF_CONN,\r\n mutation.ADD_BACK_CONN,\r\n mutation.SUB_BACK_CONN,\r\n mutation.SWAP_NODES\r\n];\r\n\r\nmutation.FFW = [\r\n mutation.ADD_NODE,\r\n mutation.SUB_NODE,\r\n mutation.ADD_CONN,\r\n mutation.SUB_CONN,\r\n mutation.MOD_WEIGHT,\r\n mutation.MOD_BIAS,\r\n mutation.MOD_ACTIVATION,\r\n mutation.SWAP_NODES\r\n];\r\n\r\n/* Export */\r\nmodule.exports = mutation;\r\n", "/*******************************************************************************\r\n SELECTION\r\n*******************************************************************************/\r\n\r\n// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm)\r\n\r\nvar selection = {\r\n FITNESS_PROPORTIONATE: {\r\n name: 'FITNESS_PROPORTIONATE'\r\n },\r\n POWER: {\r\n name: 'POWER',\r\n power: 4\r\n },\r\n TOURNAMENT: {\r\n name: 'TOURNAMENT',\r\n size: 5,\r\n probability: 0.5\r\n }\r\n};\r\n\r\n/* Export */\r\nmodule.exports = selection;\r\n", "/*******************************************************************************\r\n CROSSOVER\r\n*******************************************************************************/\r\n\r\n// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm)\r\nvar crossover = {\r\n SINGLE_POINT: {\r\n name: 'SINGLE_POINT',\r\n config: [0.4]\r\n },\r\n TWO_POINT: {\r\n name: 'TWO_POINT',\r\n config: [0.4, 0.9]\r\n },\r\n UNIFORM: {\r\n name: 'UNIFORM'\r\n },\r\n AVERAGE: {\r\n name: 'AVERAGE'\r\n }\r\n};\r\n\r\n/* Export */\r\nmodule.exports = crossover;\r\n", "/*******************************************************************************\r\n COST FUNCTIONS\r\n*******************************************************************************/\r\n\r\n// https://en.wikipedia.org/wiki/Loss_function\r\nvar cost = {\r\n // Cross entropy error\r\n CROSS_ENTROPY: function (target, output) {\r\n var error = 0;\r\n for (var i = 0; i < output.length; i++) {\r\n // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A\r\n error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15));\r\n }\r\n return error / output.length;\r\n },\r\n // Mean Squared Error\r\n MSE: function (target, output) {\r\n var error = 0;\r\n for (var i = 0; i < output.length; i++) {\r\n error += Math.pow(target[i] - output[i], 2);\r\n }\r\n\r\n return error / output.length;\r\n },\r\n // Binary error\r\n BINARY: function (target, output) {\r\n var misses = 0;\r\n for (var i = 0; i < output.length; i++) {\r\n misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2);\r\n }\r\n\r\n return misses;\r\n },\r\n // Mean Absolute Error\r\n MAE: function (target, output) {\r\n var error = 0;\r\n for (var i = 0; i < output.length; i++) {\r\n error += Math.abs(target[i] - output[i]);\r\n }\r\n\r\n return error / output.length;\r\n },\r\n // Mean Absolute Percentage Error\r\n MAPE: function (target, output) {\r\n var error = 0;\r\n for (var i = 0; i < output.length; i++) {\r\n error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15));\r\n }\r\n\r\n return error / output.length;\r\n },\r\n // Mean Squared Logarithmic Error\r\n MSLE: function (target, output) {\r\n var error = 0;\r\n for (var i = 0; i < output.length; i++) {\r\n error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15));\r\n }\r\n\r\n return error;\r\n },\r\n // Hinge loss, for classifiers\r\n HINGE: function (target, output) {\r\n var error = 0;\r\n for (var i = 0; i < output.length; i++) {\r\n error += Math.max(0, 1 - target[i] * output[i]);\r\n }\r\n\r\n return error;\r\n }\r\n};\r\n\r\n/* Export */\r\nmodule.exports = cost;\r\n", "/*******************************************************************************\r\n GATING\r\n*******************************************************************************/\r\n\r\n// Specifies how to gate a connection between two groups of multiple neurons\r\nvar gating = {\r\n OUTPUT: {\r\n name: 'OUTPUT'\r\n },\r\n INPUT: {\r\n name: 'INPUT'\r\n },\r\n SELF: {\r\n name: 'SELF'\r\n }\r\n};\r\n\r\n/* Export */\r\nmodule.exports = gating;\r\n", "/*******************************************************************************\r\n CONNECTION\r\n*******************************************************************************/\r\n\r\n// Specifies in what manner two groups are connected\r\nvar connection = {\r\n ALL_TO_ALL: {\r\n name: 'OUTPUT'\r\n },\r\n ALL_TO_ELSE: {\r\n name: 'INPUT'\r\n },\r\n ONE_TO_ONE: {\r\n name: 'SELF'\r\n }\r\n};\r\n\r\n/* Export */\r\nmodule.exports = connection;\r\n", "/*******************************************************************************\r\n RATE\r\n*******************************************************************************/\r\n\r\n// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244\r\nvar rate = {\r\n FIXED: function () {\r\n var func = function (baseRate, iteration) { return baseRate; };\r\n return func;\r\n },\r\n STEP: function (gamma, stepSize) {\r\n gamma = gamma || 0.9;\r\n stepSize = stepSize || 100;\r\n\r\n var func = function (baseRate, iteration) {\r\n return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize));\r\n };\r\n\r\n return func;\r\n },\r\n EXP: function (gamma) {\r\n gamma = gamma || 0.999;\r\n\r\n var func = function (baseRate, iteration) {\r\n return baseRate * Math.pow(gamma, iteration);\r\n };\r\n\r\n return func;\r\n },\r\n INV: function (gamma, power) {\r\n gamma = gamma || 0.001;\r\n power = power || 2;\r\n\r\n var func = function (baseRate, iteration) {\r\n return baseRate * Math.pow(1 + gamma * iteration, -power);\r\n };\r\n\r\n return func;\r\n }\r\n};\r\n\r\n/* Export */\r\nmodule.exports = rate;\r\n", "/*******************************************************************************\r\n METHODS\r\n*******************************************************************************/\r\n\r\nvar methods = {\r\n activation: require('./activation'),\r\n mutation: require('./mutation'),\r\n selection: require('./selection'),\r\n crossover: require('./crossover'),\r\n cost: require('./cost'),\r\n gating: require('./gating'),\r\n connection: require('./connection'),\r\n rate: require('./rate')\r\n};\r\n\r\n/** Export */\r\nmodule.exports = methods;\r\n", "/* Export */\r\nmodule.exports = Connection;\r\n\r\n/*******************************************************************************\r\n CONNECTION\r\n*******************************************************************************/\r\n\r\nfunction Connection (from, to, weight) {\r\n this.from = from;\r\n this.to = to;\r\n this.gain = 1;\r\n\r\n this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight;\r\n\r\n this.gater = null;\r\n this.elegibility = 0;\r\n\r\n // For tracking momentum\r\n this.previousDeltaWeight = 0;\r\n\r\n // Batch training\r\n this.totalDeltaWeight = 0;\r\n\r\n this.xtrace = {\r\n nodes: [],\r\n values: []\r\n };\r\n}\r\n\r\nConnection.prototype = {\r\n /**\r\n * Converts the connection to a json object\r\n */\r\n toJSON: function () {\r\n var json = {\r\n weight: this.weight\r\n };\r\n\r\n return json;\r\n }\r\n};\r\n\r\n/**\r\n * Returns an innovation ID\r\n * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function)\r\n */\r\nConnection.innovationID = function (a, b) {\r\n return 1 / 2 * (a + b) * (a + b + 1) + b;\r\n};\r\n", "export default new Proxy({}, {\n get() {\n throw new Error('Module \"child_process\" has been externalized for browser compatibility and cannot be accessed in client code.')\n }\n})", "export default new Proxy({}, {\n get() {\n throw new Error('Module \"path\" has been externalized for browser compatibility and cannot be accessed in client code.')\n }\n})", "/* Export */\r\nmodule.exports = TestWorker;\r\n\r\n/* Import */\r\nvar cp = require('child_process');\r\nvar path = require('path');\r\n\r\n/*******************************************************************************\r\n WEBWORKER\r\n*******************************************************************************/\r\n\r\nfunction TestWorker (dataSet, cost) {\r\n this.worker = cp.fork(path.join(__dirname, '/worker'));\r\n\r\n this.worker.send({ set: dataSet, cost: cost.name });\r\n}\r\n\r\nTestWorker.prototype = {\r\n evaluate: function (network) {\r\n return new Promise((resolve, reject) => {\r\n var serialized = network.serialize();\r\n\r\n var data = {\r\n activations: serialized[0],\r\n states: serialized[1],\r\n conns: serialized[2]\r\n };\r\n\r\n var _that = this.worker;\r\n this.worker.on('message', function callback (e) {\r\n _that.removeListener('message', callback);\r\n resolve(e);\r\n });\r\n\r\n this.worker.send(data);\r\n });\r\n },\r\n\r\n terminate: function () {\r\n this.worker.kill();\r\n }\r\n};\r\n", "/* Export */\r\nmodule.exports = TestWorker;\r\n\r\n/* Import */\r\nvar multi = require('../../multi');\r\n\r\n/*******************************************************************************\r\n WEBWORKER\r\n*******************************************************************************/\r\n\r\nfunction TestWorker (dataSet, cost) {\r\n var blob = new Blob([this._createBlobString(cost)]);\r\n this.url = window.URL.createObjectURL(blob);\r\n this.worker = new Worker(this.url);\r\n\r\n var data = { set: new Float64Array(dataSet).buffer };\r\n this.worker.postMessage(data, [data.set]);\r\n}\r\n\r\nTestWorker.prototype = {\r\n evaluate: function (network) {\r\n return new Promise((resolve, reject) => {\r\n var serialized = network.serialize();\r\n\r\n var data = {\r\n activations: new Float64Array(serialized[0]).buffer,\r\n states: new Float64Array(serialized[1]).buffer,\r\n conns: new Float64Array(serialized[2]).buffer\r\n };\r\n\r\n this.worker.onmessage = function (e) {\r\n var error = new Float64Array(e.data.buffer)[0];\r\n resolve(error);\r\n };\r\n\r\n this.worker.postMessage(data, [data.activations, data.states, data.conns]);\r\n });\r\n },\r\n\r\n terminate: function () {\r\n this.worker.terminate();\r\n window.URL.revokeObjectURL(this.url);\r\n },\r\n\r\n _createBlobString: function (cost) {\r\n var source = `\r\n var F = [${multi.activations.toString()}];\r\n var cost = ${cost.toString()};\r\n var multi = {\r\n deserializeDataSet: ${multi.deserializeDataSet.toString()},\r\n testSerializedSet: ${multi.testSerializedSet.toString()},\r\n activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()}\r\n };\r\n\r\n this.onmessage = function (e) {\r\n if(typeof e.data.set === 'undefined'){\r\n var A = new Float64Array(e.data.activations);\r\n var S = new Float64Array(e.data.states);\r\n var data = new Float64Array(e.data.conns);\r\n\r\n var error = multi.testSerializedSet(set, cost, A, S, data, F);\r\n\r\n var answer = { buffer: new Float64Array([error ]).buffer };\r\n postMessage(answer, [answer.buffer]);\r\n } else {\r\n set = multi.deserializeDataSet(new Float64Array(e.data.set));\r\n }\r\n };`;\r\n\r\n return source;\r\n }\r\n};\r\n", "/*******************************************************************************\r\n WORKERS\r\n*******************************************************************************/\r\n\r\nvar workers = {\r\n node: {\r\n TestWorker: require('./node/testworker')\r\n },\r\n browser: {\r\n TestWorker: require('./browser/testworker')\r\n }\r\n};\r\n\r\n/** Export */\r\nmodule.exports = workers;\r\n", "/*******************************************************************************\r\n MULTITHREADING\r\n*******************************************************************************/\r\n\r\nvar multi = {\r\n /** Workers */\r\n workers: require('./workers/workers'),\r\n\r\n /** Serializes a dataset */\r\n serializeDataSet: function (dataSet) {\r\n var serialized = [dataSet[0].input.length, dataSet[0].output.length];\r\n\r\n for (var i = 0; i < dataSet.length; i++) {\r\n var j;\r\n for (j = 0; j < serialized[0]; j++) {\r\n serialized.push(dataSet[i].input[j]);\r\n }\r\n for (j = 0; j < serialized[1]; j++) {\r\n serialized.push(dataSet[i].output[j]);\r\n }\r\n }\r\n\r\n return serialized;\r\n },\r\n\r\n /** Activate a serialized network */\r\n activateSerializedNetwork: function (input, A, S, data, F) {\r\n for (var i = 0; i < data[0]; i++) A[i] = input[i];\r\n for (i = 2; i < data.length; i++) {\r\n let index = data[i++];\r\n let bias = data[i++];\r\n let squash = data[i++];\r\n let selfweight = data[i++];\r\n let selfgater = data[i++];\r\n\r\n S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias;\r\n\r\n while (data[i] !== -2) {\r\n S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]);\r\n }\r\n A[index] = F[squash](S[index]);\r\n }\r\n\r\n var output = [];\r\n for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]);\r\n return output;\r\n },\r\n\r\n /** Deserializes a dataset to an array of arrays */\r\n deserializeDataSet: function (serializedSet) {\r\n var set = [];\r\n\r\n var sampleSize = serializedSet[0] + serializedSet[1];\r\n for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) {\r\n let input = [];\r\n for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) {\r\n input.push(serializedSet[j]);\r\n }\r\n let output = [];\r\n for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) {\r\n output.push(serializedSet[j]);\r\n }\r\n set.push(input);\r\n set.push(output);\r\n }\r\n\r\n return set;\r\n },\r\n\r\n /** A list of compiled activation functions in a certain order */\r\n activations: [\r\n function (x) { return 1 / (1 + Math.exp(-x)); },\r\n function (x) { return Math.tanh(x); },\r\n function (x) { return x; },\r\n function (x) { return x > 0 ? 1 : 0; },\r\n function (x) { return x > 0 ? x : 0; },\r\n function (x) { return x / (1 + Math.abs(x)); },\r\n function (x) { return Math.sin(x); },\r\n function (x) { return Math.exp(-Math.pow(x, 2)); },\r\n function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; },\r\n function (x) { return x > 0 ? 1 : -1; },\r\n function (x) { return 2 / (1 + Math.exp(-x)) - 1; },\r\n function (x) { return Math.max(-1, Math.min(1, x)); },\r\n function (x) { return Math.abs(x); },\r\n function (x) { return 1 - x; },\r\n function (x) {\r\n var a = 1.6732632423543772848170429916717;\r\n return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946;\r\n }\r\n ]\r\n};\r\n\r\nmulti.testSerializedSet = function (set, cost, A, S, data, F) {\r\n // Calculate how much samples are in the set\r\n var error = 0;\r\n for (var i = 0; i < set.length; i += 2) {\r\n let output = multi.activateSerializedNetwork(set[i], A, S, data, F);\r\n error += cost(set[i + 1], output);\r\n }\r\n\r\n return error / (set.length / 2);\r\n};\r\n\r\n/* Export */\r\nfor (var i in multi) {\r\n module.exports[i] = multi[i];\r\n}\r\n", "/*******************************************************************************\r\n CONFIG\r\n*******************************************************************************/\r\n\r\n// Config\r\nvar config = {\r\n warnings: false\r\n};\r\n\r\n/* Export */\r\nmodule.exports = config;\r\n", "/* Export */\r\nmodule.exports = Neat;\r\n\r\n/* Import */\r\nvar Network = require('./architecture/network');\r\nvar methods = require('./methods/methods');\r\nvar config = require('./config');\r\n\r\n/* Easier variable naming */\r\nvar selection = methods.selection;\r\n\r\n/*******************************************************************************\r\n NEAT\r\n*******************************************************************************/\r\n\r\nfunction Neat (input, output, fitness, options) {\r\n this.input = input; // The input size of the networks\r\n this.output = output; // The output size of the networks\r\n this.fitness = fitness; // The fitness function to evaluate the networks\r\n\r\n // Configure options\r\n options = options || {};\r\n this.equal = options.equal || false;\r\n this.clear = options.clear || false;\r\n this.popsize = options.popsize || 50;\r\n this.elitism = options.elitism || 0;\r\n this.provenance = options.provenance || 0;\r\n this.mutationRate = options.mutationRate || 0.3;\r\n this.mutationAmount = options.mutationAmount || 1;\r\n\r\n this.fitnessPopulation = options.fitnessPopulation || false;\r\n\r\n this.selection = options.selection || methods.selection.POWER;\r\n this.crossover = options.crossover || [\r\n methods.crossover.SINGLE_POINT,\r\n methods.crossover.TWO_POINT,\r\n methods.crossover.UNIFORM,\r\n methods.crossover.AVERAGE\r\n ];\r\n this.mutation = options.mutation || methods.mutation.FFW;\r\n\r\n this.template = options.network || false;\r\n\r\n this.maxNodes = options.maxNodes || Infinity;\r\n this.maxConns = options.maxConns || Infinity;\r\n this.maxGates = options.maxGates || Infinity;\r\n\r\n // Custom mutation selection function if given\r\n this.selectMutationMethod = typeof options.mutationSelection === 'function' ? options.mutationSelection.bind(this) : this.selectMutationMethod;\r\n\r\n // Generation counter\r\n this.generation = 0;\r\n\r\n // Initialise the genomes\r\n this.createPool(this.template);\r\n}\r\n\r\nNeat.prototype = {\r\n /**\r\n * Create the initial pool of genomes\r\n */\r\n createPool: function (network) {\r\n this.population = [];\r\n\r\n for (var i = 0; i < this.popsize; i++) {\r\n var copy;\r\n if (this.template) {\r\n copy = Network.fromJSON(network.toJSON());\r\n } else {\r\n copy = new Network(this.input, this.output);\r\n }\r\n copy.score = undefined;\r\n this.population.push(copy);\r\n }\r\n },\r\n\r\n /**\r\n * Evaluates, selects, breeds and mutates population\r\n */\r\n evolve: async function () {\r\n // Check if evaluated, sort the population\r\n if (typeof this.population[this.population.length - 1].score === 'undefined') {\r\n await this.evaluate();\r\n }\r\n this.sort();\r\n\r\n var fittest = Network.fromJSON(this.population[0].toJSON());\r\n fittest.score = this.population[0].score;\r\n\r\n var newPopulation = [];\r\n\r\n // Elitism\r\n var elitists = [];\r\n for (var i = 0; i < this.elitism; i++) {\r\n elitists.push(this.population[i]);\r\n }\r\n\r\n // Provenance\r\n for (i = 0; i < this.provenance; i++) {\r\n newPopulation.push(Network.fromJSON(this.template.toJSON()));\r\n }\r\n\r\n // Breed the next individuals\r\n for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) {\r\n newPopulation.push(this.getOffspring());\r\n }\r\n\r\n // Replace the old population with the new population\r\n this.population = newPopulation;\r\n this.mutate();\r\n\r\n this.population.push(...elitists);\r\n\r\n // Reset the scores\r\n for (i = 0; i < this.population.length; i++) {\r\n this.population[i].score = undefined;\r\n }\r\n\r\n this.generation++;\r\n\r\n return fittest;\r\n },\r\n\r\n /**\r\n * Breeds two parents into an offspring, population MUST be surted\r\n */\r\n getOffspring: function () {\r\n var parent1 = this.getParent();\r\n var parent2 = this.getParent();\r\n\r\n return Network.crossOver(parent1, parent2, this.equal);\r\n },\r\n\r\n /**\r\n * Selects a random mutation method for a genome according to the parameters\r\n */\r\n selectMutationMethod: function (genome) {\r\n var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)];\r\n\r\n if (mutationMethod === methods.mutation.ADD_NODE && genome.nodes.length >= this.maxNodes) {\r\n if (config.warnings) console.warn('maxNodes exceeded!');\r\n return;\r\n }\r\n\r\n if (mutationMethod === methods.mutation.ADD_CONN && genome.connections.length >= this.maxConns) {\r\n if (config.warnings) console.warn('maxConns exceeded!');\r\n return;\r\n }\r\n\r\n if (mutationMethod === methods.mutation.ADD_GATE && genome.gates.length >= this.maxGates) {\r\n if (config.warnings) console.warn('maxGates exceeded!');\r\n return;\r\n }\r\n\r\n return mutationMethod;\r\n },\r\n\r\n /**\r\n * Mutates the given (or current) population\r\n */\r\n mutate: function () {\r\n // Elitist genomes should not be included\r\n for (var i = 0; i < this.population.length; i++) {\r\n if (Math.random() <= this.mutationRate) {\r\n for (var j = 0; j < this.mutationAmount; j++) {\r\n var mutationMethod = this.selectMutationMethod(this.population[i]);\r\n this.population[i].mutate(mutationMethod);\r\n }\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * Evaluates the current population\r\n */\r\n evaluate: async function () {\r\n var i;\r\n if (this.fitnessPopulation) {\r\n if (this.clear) {\r\n for (i = 0; i < this.population.length; i++) {\r\n this.population[i].clear();\r\n }\r\n }\r\n await this.fitness(this.population);\r\n } else {\r\n for (i = 0; i < this.population.length; i++) {\r\n var genome = this.population[i];\r\n if (this.clear) genome.clear();\r\n genome.score = await this.fitness(genome);\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * Sorts the population by score\r\n */\r\n sort: function () {\r\n this.population.sort(function (a, b) {\r\n return b.score - a.score;\r\n });\r\n },\r\n\r\n /**\r\n * Returns the fittest genome of the current population\r\n */\r\n getFittest: function () {\r\n // Check if evaluated\r\n if (typeof this.population[this.population.length - 1].score === 'undefined') {\r\n this.evaluate();\r\n }\r\n if (this.population[0].score < this.population[1].score) {\r\n this.sort();\r\n }\r\n\r\n return this.population[0];\r\n },\r\n\r\n /**\r\n * Returns the average fitness of the current population\r\n */\r\n getAverage: function () {\r\n if (typeof this.population[this.population.length - 1].score === 'undefined') {\r\n this.evaluate();\r\n }\r\n\r\n var score = 0;\r\n for (var i = 0; i < this.population.length; i++) {\r\n score += this.population[i].score;\r\n }\r\n\r\n return score / this.population.length;\r\n },\r\n\r\n /**\r\n * Gets a genome based on the selection function\r\n * @return {Network} genome\r\n */\r\n getParent: function () {\r\n var i;\r\n switch (this.selection) {\r\n case selection.POWER:\r\n if (this.population[0].score < this.population[1].score) this.sort();\r\n\r\n var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length);\r\n return this.population[index];\r\n case selection.FITNESS_PROPORTIONATE:\r\n // As negative fitnesses are possible\r\n // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values\r\n // this is unnecessarily run for every individual, should be changed\r\n\r\n var totalFitness = 0;\r\n var minimalFitness = 0;\r\n for (i = 0; i < this.population.length; i++) {\r\n var score = this.population[i].score;\r\n minimalFitness = score < minimalFitness ? score : minimalFitness;\r\n totalFitness += score;\r\n }\r\n\r\n minimalFitness = Math.abs(minimalFitness);\r\n totalFitness += minimalFitness * this.population.length;\r\n\r\n var random = Math.random() * totalFitness;\r\n var value = 0;\r\n\r\n for (i = 0; i < this.population.length; i++) {\r\n let genome = this.population[i];\r\n value += genome.score + minimalFitness;\r\n if (random < value) return genome;\r\n }\r\n\r\n // if all scores equal, return random genome\r\n return this.population[Math.floor(Math.random() * this.population.length)];\r\n case selection.TOURNAMENT:\r\n if (this.selection.size > this.popsize) {\r\n throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size');\r\n }\r\n\r\n // Create a tournament\r\n var individuals = [];\r\n for (i = 0; i < this.selection.size; i++) {\r\n let random = this.population[Math.floor(Math.random() * this.population.length)];\r\n individuals.push(random);\r\n }\r\n\r\n // Sort the tournament individuals by score\r\n individuals.sort(function (a, b) {\r\n return b.score - a.score;\r\n });\r\n\r\n // Select an individual\r\n for (i = 0; i < this.selection.size; i++) {\r\n if (Math.random() < this.selection.probability || i === this.selection.size - 1) {\r\n return individuals[i];\r\n }\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * Export the current population to a json object\r\n */\r\n export: function () {\r\n var json = [];\r\n for (var i = 0; i < this.population.length; i++) {\r\n var genome = this.population[i];\r\n json.push(genome.toJSON());\r\n }\r\n\r\n return json;\r\n },\r\n\r\n /**\r\n * Import population from a json object\r\n */\r\n import: function (json) {\r\n var population = [];\r\n for (var i = 0; i < json.length; i++) {\r\n var genome = json[i];\r\n population.push(Network.fromJSON(genome));\r\n }\r\n this.population = population;\r\n this.popsize = population.length;\r\n }\r\n};\r\n", "/* Export */\r\nmodule.exports = Node;\r\n\r\n/* Import */\r\nvar methods = require('../methods/methods');\r\nvar Connection = require('./connection');\r\nvar config = require('../config');\r\n\r\n/*******************************************************************************\r\n NODE\r\n*******************************************************************************/\r\n\r\nfunction Node (type) {\r\n this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1;\r\n this.squash = methods.activation.LOGISTIC;\r\n this.type = type || 'hidden';\r\n\r\n this.activation = 0;\r\n this.state = 0;\r\n this.old = 0;\r\n\r\n // For dropout\r\n this.mask = 1;\r\n\r\n // For tracking momentum\r\n this.previousDeltaBias = 0;\r\n\r\n // Batch training\r\n this.totalDeltaBias = 0;\r\n\r\n this.connections = {\r\n in: [],\r\n out: [],\r\n gated: [],\r\n self: new Connection(this, this, 0)\r\n };\r\n\r\n // Data for backpropagation\r\n this.error = {\r\n responsibility: 0,\r\n projected: 0,\r\n gated: 0\r\n };\r\n}\r\n\r\nNode.prototype = {\r\n /**\r\n * Activates the node\r\n */\r\n activate: function (input) {\r\n // Check if an input is given\r\n if (typeof input !== 'undefined') {\r\n this.activation = input;\r\n return this.activation;\r\n }\r\n\r\n this.old = this.state;\r\n\r\n // All activation sources coming from the node itself\r\n this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias;\r\n\r\n // Activation sources coming from connections\r\n var i;\r\n for (i = 0; i < this.connections.in.length; i++) {\r\n var connection = this.connections.in[i];\r\n this.state += connection.from.activation * connection.weight * connection.gain;\r\n }\r\n\r\n // Squash the values received\r\n this.activation = this.squash(this.state) * this.mask;\r\n this.derivative = this.squash(this.state, true);\r\n\r\n // Update traces\r\n var nodes = [];\r\n var influences = [];\r\n\r\n for (i = 0; i < this.connections.gated.length; i++) {\r\n let conn = this.connections.gated[i];\r\n let node = conn.to;\r\n\r\n let index = nodes.indexOf(node);\r\n if (index > -1) {\r\n influences[index] += conn.weight * conn.from.activation;\r\n } else {\r\n nodes.push(node);\r\n influences.push(conn.weight * conn.from.activation +\r\n (node.connections.self.gater === this ? node.old : 0));\r\n }\r\n\r\n // Adjust the gain to this nodes' activation\r\n conn.gain = this.activation;\r\n }\r\n\r\n for (i = 0; i < this.connections.in.length; i++) {\r\n let connection = this.connections.in[i];\r\n\r\n // Elegibility trace\r\n connection.elegibility = this.connections.self.gain * this.connections.self.weight *\r\n connection.elegibility + connection.from.activation * connection.gain;\r\n\r\n // Extended trace\r\n for (var j = 0; j < nodes.length; j++) {\r\n let node = nodes[j];\r\n let influence = influences[j];\r\n\r\n let index = connection.xtrace.nodes.indexOf(node);\r\n\r\n if (index > -1) {\r\n connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight *\r\n connection.xtrace.values[index] + this.derivative * connection.elegibility * influence;\r\n } else {\r\n // Does not exist there yet, might be through mutation\r\n connection.xtrace.nodes.push(node);\r\n connection.xtrace.values.push(this.derivative * connection.elegibility * influence);\r\n }\r\n }\r\n }\r\n\r\n return this.activation;\r\n },\r\n\r\n /**\r\n * Activates the node without calculating elegibility traces and such\r\n */\r\n noTraceActivate: function (input) {\r\n // Check if an input is given\r\n if (typeof input !== 'undefined') {\r\n this.activation = input;\r\n return this.activation;\r\n }\r\n\r\n // All activation sources coming from the node itself\r\n this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias;\r\n\r\n // Activation sources coming from connections\r\n var i;\r\n for (i = 0; i < this.connections.in.length; i++) {\r\n var connection = this.connections.in[i];\r\n this.state += connection.from.activation * connection.weight * connection.gain;\r\n }\r\n\r\n // Squash the values received\r\n this.activation = this.squash(this.state);\r\n\r\n for (i = 0; i < this.connections.gated.length; i++) {\r\n this.connections.gated[i].gain = this.activation;\r\n }\r\n\r\n return this.activation;\r\n },\r\n\r\n /**\r\n * Back-propagate the error, aka learn\r\n */\r\n propagate: function (rate, momentum, update, target) {\r\n momentum = momentum || 0;\r\n rate = rate || 0.3;\r\n\r\n // Error accumulator\r\n var error = 0;\r\n\r\n // Output nodes get their error from the enviroment\r\n if (this.type === 'output') {\r\n this.error.responsibility = this.error.projected = target - this.activation;\r\n } else { // the rest of the nodes compute their error responsibilities by backpropagation\r\n // error responsibilities from all the connections projected from this node\r\n var i;\r\n for (i = 0; i < this.connections.out.length; i++) {\r\n let connection = this.connections.out[i];\r\n let node = connection.to;\r\n // Eq. 21\r\n error += node.error.responsibility * connection.weight * connection.gain;\r\n }\r\n\r\n // Projected error responsibility\r\n this.error.projected = this.derivative * error;\r\n\r\n // Error responsibilities from all connections gated by this neuron\r\n error = 0;\r\n\r\n for (i = 0; i < this.connections.gated.length; i++) {\r\n let conn = this.connections.gated[i];\r\n let node = conn.to;\r\n let influence = node.connections.self.gater === this ? node.old : 0;\r\n\r\n influence += conn.weight * conn.from.activation;\r\n error += node.error.responsibility * influence;\r\n }\r\n\r\n // Gated error responsibility\r\n this.error.gated = this.derivative * error;\r\n\r\n // Error responsibility\r\n this.error.responsibility = this.error.projected + this.error.gated;\r\n }\r\n\r\n if (this.type === 'constant') return;\r\n\r\n // Adjust all the node's incoming connections\r\n for (i = 0; i < this.connections.in.length; i++) {\r\n let connection = this.connections.in[i];\r\n\r\n let gradient = this.error.projected * connection.elegibility;\r\n\r\n for (var j = 0; j < connection.xtrace.nodes.length; j++) {\r\n let node = connection.xtrace.nodes[j];\r\n let value = connection.xtrace.values[j];\r\n gradient += node.error.responsibility * value;\r\n }\r\n\r\n // Adjust weight\r\n let deltaWeight = rate * gradient * this.mask;\r\n connection.totalDeltaWeight += deltaWeight;\r\n if (update) {\r\n connection.totalDeltaWeight += momentum * connection.previousDeltaWeight;\r\n connection.weight += connection.totalDeltaWeight;\r\n connection.previousDeltaWeight = connection.totalDeltaWeight;\r\n connection.totalDeltaWeight = 0;\r\n }\r\n }\r\n\r\n // Adjust bias\r\n var deltaBias = rate * this.error.responsibility;\r\n this.totalDeltaBias += deltaBias;\r\n if (update) {\r\n this.totalDeltaBias += momentum * this.previousDeltaBias;\r\n this.bias += this.totalDeltaBias;\r\n this.previousDeltaBias = this.totalDeltaBias;\r\n this.totalDeltaBias = 0;\r\n }\r\n },\r\n\r\n /**\r\n * Creates a connection from this node to the given node\r\n */\r\n connect: function (target, weight) {\r\n var connections = [];\r\n if (typeof target.bias !== 'undefined') { // must be a node!\r\n if (target === this) {\r\n // Turn on the self connection by setting the weight\r\n if (this.connections.self.weight !== 0) {\r\n if (config.warnings) console.warn('This connection already exists!');\r\n } else {\r\n this.connections.self.weight = weight || 1;\r\n }\r\n connections.push(this.connections.self);\r\n } else if (this.isProjectingTo(target)) {\r\n throw new Error('Already projecting a connection to this node!');\r\n } else {\r\n let connection = new Connection(this, target, weight);\r\n target.connections.in.push(connection);\r\n this.connections.out.push(connection);\r\n\r\n connections.push(connection);\r\n }\r\n } else { // should be a group\r\n for (var i = 0; i < target.nodes.length; i++) {\r\n let connection = new Connection(this, target.nodes[i], weight);\r\n target.nodes[i].connections.in.push(connection);\r\n this.connections.out.push(connection);\r\n target.connections.in.push(connection);\r\n\r\n connections.push(connection);\r\n }\r\n }\r\n return connections;\r\n },\r\n\r\n /**\r\n * Disconnects this node from the other node\r\n */\r\n disconnect: function (node, twosided) {\r\n if (this === node) {\r\n this.connections.self.weight = 0;\r\n return;\r\n }\r\n\r\n for (var i = 0; i < this.connections.out.length; i++) {\r\n let conn = this.connections.out[i];\r\n if (conn.to === node) {\r\n this.connections.out.splice(i, 1);\r\n let j = conn.to.connections.in.indexOf(conn);\r\n conn.to.connections.in.splice(j, 1);\r\n if (conn.gater !== null) conn.gater.ungate(conn);\r\n break;\r\n }\r\n }\r\n\r\n if (twosided) {\r\n node.disconnect(this);\r\n }\r\n },\r\n\r\n /**\r\n * Make this node gate a connection\r\n */\r\n gate: function (connections) {\r\n if (!Array.isArray(connections)) {\r\n connections = [connections];\r\n }\r\n\r\n for (var i = 0; i < connections.length; i++) {\r\n var connection = connections[i];\r\n\r\n this.connections.gated.push(connection);\r\n connection.gater = this;\r\n }\r\n },\r\n\r\n /**\r\n * Removes the gates from this node from the given connection(s)\r\n */\r\n ungate: function (connections) {\r\n if (!Array.isArray(connections)) {\r\n connections = [connections];\r\n }\r\n\r\n for (var i = connections.length - 1; i >= 0; i--) {\r\n var connection = connections[i];\r\n\r\n var index = this.connections.gated.indexOf(connection);\r\n this.connections.gated.splice(index, 1);\r\n connection.gater = null;\r\n connection.gain = 1;\r\n }\r\n },\r\n\r\n /**\r\n * Clear the context of the node\r\n */\r\n clear: function () {\r\n for (var i = 0; i < this.connections.in.length; i++) {\r\n var connection = this.connections.in[i];\r\n\r\n connection.elegibility = 0;\r\n connection.xtrace = {\r\n nodes: [],\r\n values: []\r\n };\r\n }\r\n\r\n for (i = 0; i < this.connections.gated.length; i++) {\r\n let conn = this.connections.gated[i];\r\n conn.gain = 0;\r\n }\r\n\r\n this.error.responsibility = this.error.projected = this.error.gated = 0;\r\n this.old = this.state = this.activation = 0;\r\n },\r\n\r\n /**\r\n * Mutates the node with the given method\r\n */\r\n mutate: function (method) {\r\n if (typeof method === 'undefined') {\r\n throw new Error('No mutate method given!');\r\n } else if (!(method.name in methods.mutation)) {\r\n throw new Error('This method does not exist!');\r\n }\r\n\r\n switch (method) {\r\n case methods.mutation.MOD_ACTIVATION:\r\n // Can't be the same squash\r\n var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length];\r\n this.squash = squash;\r\n break;\r\n case methods.mutation.MOD_BIAS:\r\n var modification = Math.random() * (method.max - method.min) + method.min;\r\n this.bias += modification;\r\n break;\r\n }\r\n },\r\n\r\n /**\r\n * Checks if this node is projecting to the given node\r\n */\r\n isProjectingTo: function (node) {\r\n if (node === this && this.connections.self.weight !== 0) return true;\r\n\r\n for (var i = 0; i < this.connections.out.length; i++) {\r\n var conn = this.connections.out[i];\r\n if (conn.to === node) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n },\r\n\r\n /**\r\n * Checks if the given node is projecting to this node\r\n */\r\n isProjectedBy: function (node) {\r\n if (node === this && this.connections.self.weight !== 0) return true;\r\n\r\n for (var i = 0; i < this.connections.in.length; i++) {\r\n var conn = this.connections.in[i];\r\n if (conn.from === node) {\r\n return true;\r\n }\r\n }\r\n\r\n return false;\r\n },\r\n\r\n /**\r\n * Converts the node to a json object\r\n */\r\n toJSON: function () {\r\n var json = {\r\n bias: this.bias,\r\n type: this.type,\r\n squash: this.squash.name,\r\n mask: this.mask\r\n };\r\n\r\n return json;\r\n }\r\n};\r\n\r\n/**\r\n * Convert a json object to a node\r\n */\r\nNode.fromJSON = function (json) {\r\n var node = new Node();\r\n node.bias = json.bias;\r\n node.type = json.type;\r\n node.mask = json.mask;\r\n node.squash = methods.activation[json.squash];\r\n\r\n return node;\r\n};\r\n", "export default new Proxy({}, {\n get() {\n throw new Error('Module \"os\" has been externalized for browser compatibility and cannot be accessed in client code.')\n }\n})", "/* Export */\r\nmodule.exports = Network;\r\n\r\n/* Import */\r\nvar multi = require('../multithreading/multi');\r\nvar methods = require('../methods/methods');\r\nvar Connection = require('./connection');\r\nvar config = require('../config');\r\nvar Neat = require('../neat');\r\nvar Node = require('./node');\r\n\r\n/* Easier variable naming */\r\nvar mutation = methods.mutation;\r\n\r\n/*******************************************************************************\r\n NETWORK\r\n*******************************************************************************/\r\n\r\nfunction Network (input, output) {\r\n if (typeof input === 'undefined' || typeof output === 'undefined') {\r\n throw new Error('No input or output size given');\r\n }\r\n\r\n this.input = input;\r\n this.output = output;\r\n\r\n // Store all the node and connection genes\r\n this.nodes = []; // Stored in activation order\r\n this.connections = [];\r\n this.gates = [];\r\n this.selfconns = [];\r\n\r\n // Regularization\r\n this.dropout = 0;\r\n\r\n // Create input and output nodes\r\n var i;\r\n for (i = 0; i < this.input + this.output; i++) {\r\n var type = i < this.input ? 'input' : 'output';\r\n this.nodes.push(new Node(type));\r\n }\r\n\r\n // Connect input nodes with output nodes directly\r\n for (i = 0; i < this.input; i++) {\r\n for (var j = this.input; j < this.output + this.input; j++) {\r\n // https://stats.stackexchange.com/a/248040/147931\r\n var weight = Math.random() * this.input * Math.sqrt(2 / this.input);\r\n this.connect(this.nodes[i], this.nodes[j], weight);\r\n }\r\n }\r\n}\r\n\r\nNetwork.prototype = {\r\n /**\r\n * Activates the network\r\n */\r\n activate: function (input, training) {\r\n var output = [];\r\n\r\n // Activate nodes chronologically\r\n for (var i = 0; i < this.nodes.length; i++) {\r\n if (this.nodes[i].type === 'input') {\r\n this.nodes[i].activate(input[i]);\r\n } else if (this.nodes[i].type === 'output') {\r\n var activation = this.nodes[i].activate();\r\n output.push(activation);\r\n } else {\r\n if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1;\r\n this.nodes[i].activate();\r\n }\r\n }\r\n\r\n return output;\r\n },\r\n\r\n /**\r\n * Activates the network without calculating elegibility traces and such\r\n */\r\n noTraceActivate: function (input) {\r\n var output = [];\r\n\r\n // Activate nodes chronologically\r\n for (var i = 0; i < this.nodes.length; i++) {\r\n if (this.nodes[i].type === 'input') {\r\n this.nodes[i].noTraceActivate(input[i]);\r\n } else if (this.nodes[i].type === 'output') {\r\n var activation = this.nodes[i].noTraceActivate();\r\n output.push(activation);\r\n } else {\r\n this.nodes[i].noTraceActivate();\r\n }\r\n }\r\n\r\n return output;\r\n },\r\n\r\n /**\r\n * Backpropagate the network\r\n */\r\n propagate: function (rate, momentum, update, target) {\r\n if (typeof target === 'undefined' || target.length !== this.output) {\r\n throw new Error('Output target length should match network output length');\r\n }\r\n\r\n var targetIndex = target.length;\r\n\r\n // Propagate output nodes\r\n var i;\r\n for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) {\r\n this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]);\r\n }\r\n\r\n // Propagate hidden and input nodes\r\n for (i = this.nodes.length - this.output - 1; i >= this.input; i--) {\r\n this.nodes[i].propagate(rate, momentum, update);\r\n }\r\n },\r\n\r\n /**\r\n * Clear the context of the network\r\n */\r\n clear: function () {\r\n for (var i = 0; i < this.nodes.length; i++) {\r\n this.nodes[i].clear();\r\n }\r\n },\r\n\r\n /**\r\n * Connects the from node to the to node\r\n */\r\n connect: function (from, to, weight) {\r\n var connections = from.connect(to, weight);\r\n\r\n for (var i = 0; i < connections.length; i++) {\r\n var connection = connections[i];\r\n if (from !== to) {\r\n this.connections.push(connection);\r\n } else {\r\n this.selfconns.push(connection);\r\n }\r\n }\r\n\r\n return connections;\r\n },\r\n\r\n /**\r\n * Disconnects the from node from the to node\r\n */\r\n disconnect: function (from, to) {\r\n // Delete the connection in the network's connection array\r\n var connections = from === to ? this.selfconns : this.connections;\r\n\r\n for (var i = 0; i < connections.length; i++) {\r\n var connection = connections[i];\r\n if (connection.from === from && connection.to === to) {\r\n if (connection.gater !== null) this.ungate(connection);\r\n connections.splice(i, 1);\r\n break;\r\n }\r\n }\r\n\r\n // Delete the connection at the sending and receiving neuron\r\n from.disconnect(to);\r\n },\r\n\r\n /**\r\n * Gate a connection with a node\r\n */\r\n gate: function (node, connection) {\r\n if (this.nodes.indexOf(node) === -1) {\r\n throw new Error('This node is not part of the network!');\r\n } else if (connection.gater != null) {\r\n if (config.warnings) console.warn('This connection is already gated!');\r\n return;\r\n }\r\n node.gate(connection);\r\n this.gates.push(connection);\r\n },\r\n\r\n /**\r\n * Remove the gate of a connection\r\n */\r\n ungate: function (connection) {\r\n var index = this.gates.indexOf(connection);\r\n if (index === -1) {\r\n throw new Error('This connection is not gated!');\r\n }\r\n\r\n this.gates.splice(index, 1);\r\n connection.gater.ungate(connection);\r\n },\r\n\r\n /**\r\n * Removes a node from the network\r\n */\r\n remove: function (node) {\r\n var index = this.nodes.indexOf(node);\r\n\r\n if (index === -1) {\r\n throw new Error('This node does not exist in the network!');\r\n }\r\n\r\n // Keep track of gaters\r\n var gaters = [];\r\n\r\n // Remove selfconnections from this.selfconns\r\n this.disconnect(node, node);\r\n\r\n // Get all its inputting nodes\r\n var inputs = [];\r\n for (var i = node.connections.in.length - 1; i >= 0; i--) {\r\n let connection = node.connections.in[i];\r\n if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) {\r\n gaters.push(connection.gater);\r\n }\r\n inputs.push(connection.from);\r\n this.disconnect(connection.from, node);\r\n }\r\n\r\n // Get all its outputing nodes\r\n var outputs = [];\r\n for (i = node.connections.out.length - 1; i >= 0; i--) {\r\n let connection = node.connections.out[i];\r\n if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) {\r\n gaters.push(connection.gater);\r\n }\r\n outputs.push(connection.to);\r\n this.disconnect(node, connection.to);\r\n }\r\n\r\n // Connect the input nodes to the output nodes (if not already connected)\r\n var connections = [];\r\n for (i = 0; i < inputs.length; i++) {\r\n let input = inputs[i];\r\n for (var j = 0; j < outputs.length; j++) {\r\n let output = outputs[j];\r\n if (!input.isProjectingTo(output)) {\r\n var conn = this.connect(input, output);\r\n connections.push(conn[0]);\r\n }\r\n }\r\n }\r\n\r\n // Gate random connections with gaters\r\n for (i = 0; i < gaters.length; i++) {\r\n if (connections.length === 0) break;\r\n\r\n let gater = gaters[i];\r\n let connIndex = Math.floor(Math.random() * connections.length);\r\n\r\n this.gate(gater, connections[connIndex]);\r\n connections.splice(connIndex, 1);\r\n }\r\n\r\n // Remove gated connections gated by this node\r\n for (i = node.connections.gated.length - 1; i >= 0; i--) {\r\n let conn = node.connections.gated[i];\r\n this.ungate(conn);\r\n }\r\n\r\n // Remove selfconnection\r\n this.disconnect(node, node);\r\n\r\n // Remove the node from this.nodes\r\n this.nodes.splice(index, 1);\r\n },\r\n\r\n /**\r\n * Mutates the network with the given method\r\n */\r\n mutate: function (method) {\r\n if (typeof method === 'undefined') {\r\n throw new Error('No (correct) mutate method given!');\r\n }\r\n\r\n var i, j;\r\n switch (method) {\r\n case mutation.ADD_NODE:\r\n // Look for an existing connection and place a node in between\r\n var connection = this.connections[Math.floor(Math.random() * this.connections.length)];\r\n var gater = connection.gater;\r\n this.disconnect(connection.from, connection.to);\r\n\r\n // Insert the new node right before the old connection.to\r\n var toIndex = this.nodes.indexOf(connection.to);\r\n var node = new Node('hidden');\r\n\r\n // Random squash function\r\n node.mutate(mutation.MOD_ACTIVATION);\r\n\r\n // Place it in this.nodes\r\n var minBound = Math.min(toIndex, this.nodes.length - this.output);\r\n this.nodes.splice(minBound, 0, node);\r\n\r\n // Now create two new connections\r\n var newConn1 = this.connect(connection.from, node)[0];\r\n var newConn2 = this.connect(node, connection.to)[0];\r\n\r\n // Check if the original connection was gated\r\n if (gater != null) {\r\n this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2);\r\n }\r\n break;\r\n case mutation.SUB_NODE:\r\n // Check if there are nodes left to remove\r\n if (this.nodes.length === this.input + this.output) {\r\n if (config.warnings) console.warn('No more nodes left to remove!');\r\n break;\r\n }\r\n\r\n // Select a node which isn't an input or output node\r\n var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input);\r\n this.remove(this.nodes[index]);\r\n break;\r\n case mutation.ADD_CONN:\r\n // Create an array of all uncreated (feedforward) connections\r\n var available = [];\r\n for (i = 0; i < this.nodes.length - this.output; i++) {\r\n let node1 = this.nodes[i];\r\n for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) {\r\n let node2 = this.nodes[j];\r\n if (!node1.isProjectingTo(node2)) available.push([node1, node2]);\r\n }\r\n }\r\n\r\n if (available.length === 0) {\r\n if (config.warnings) console.warn('No more connections to be made!');\r\n break;\r\n }\r\n\r\n var pair = available[Math.floor(Math.random() * available.length)];\r\n this.connect(pair[0], pair[1]);\r\n break;\r\n case mutation.SUB_CONN:\r\n // List of possible connections that can be removed\r\n var possible = [];\r\n\r\n for (i = 0; i < this.connections.length; i++) {\r\n let conn = this.connections[i];\r\n // Check if it is not disabling a node\r\n if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) {\r\n possible.push(conn);\r\n }\r\n }\r\n\r\n if (possible.length === 0) {\r\n if (config.warnings) console.warn('No connections to remove!');\r\n break;\r\n }\r\n\r\n var randomConn = possible[Math.floor(Math.random() * possible.length)];\r\n this.disconnect(randomConn.from, randomConn.to);\r\n break;\r\n case mutation.MOD_WEIGHT:\r\n var allconnections = this.connections.concat(this.selfconns);\r\n\r\n var connection = allconnections[Math.floor(Math.random() * allconnections.length)];\r\n var modification = Math.random() * (method.max - method.min) + method.min;\r\n connection.weight += modification;\r\n break;\r\n case mutation.MOD_BIAS:\r\n // Has no effect on input node, so they are excluded\r\n var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input);\r\n var node = this.nodes[index];\r\n node.mutate(method);\r\n break;\r\n case mutation.MOD_ACTIVATION:\r\n // Has no effect on input node, so they are excluded\r\n if (!method.mutateOutput && this.input + this.output === this.nodes.length) {\r\n if (config.warnings) console.warn('No nodes that allow mutation of activation function');\r\n break;\r\n }\r\n\r\n var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input);\r\n var node = this.nodes[index];\r\n\r\n node.mutate(method);\r\n break;\r\n case mutation.ADD_SELF_CONN:\r\n // Check which nodes aren't selfconnected yet\r\n var possible = [];\r\n for (i = this.input; i < this.nodes.length; i++) {\r\n let node = this.nodes[i];\r\n if (node.connections.self.weight === 0) {\r\n possible.push(node);\r\n }\r\n }\r\n\r\n if (possible.length === 0) {\r\n if (config.warnings) console.warn('No more self-connections to add!');\r\n break;\r\n }\r\n\r\n // Select a random node\r\n var node = possible[Math.floor(Math.random() * possible.length)];\r\n\r\n // Connect it to himself\r\n this.connect(node, node);\r\n break;\r\n case mutation.SUB_SELF_CONN:\r\n if (this.selfconns.length === 0) {\r\n if (config.warnings) console.warn('No more self-connections to remove!');\r\n break;\r\n }\r\n var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)];\r\n this.disconnect(conn.from, conn.to);\r\n break;\r\n case mutation.ADD_GATE:\r\n var allconnections = this.connections.concat(this.selfconns);\r\n\r\n // Create a list of all non-gated connections\r\n var possible = [];\r\n for (i = 0; i < allconnections.length; i++) {\r\n let conn = allconnections[i];\r\n if (conn.gater === null) {\r\n possible.push(conn);\r\n }\r\n }\r\n\r\n if (possible.length === 0) {\r\n if (config.warnings) console.warn('No more connections to gate!');\r\n break;\r\n }\r\n\r\n // Select a random gater node and connection, can't be gated by input\r\n var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input);\r\n var node = this.nodes[index];\r\n var conn = possible[Math.floor(Math.random() * possible.length)];\r\n\r\n // Gate the connection with the node\r\n this.gate(node, conn);\r\n break;\r\n case mutation.SUB_GATE:\r\n // Select a random gated connection\r\n if (this.gates.length === 0) {\r\n if (config.warnings) console.warn('No more connections to ungate!');\r\n break;\r\n }\r\n\r\n var index = Math.floor(Math.random() * this.gates.length);\r\n var gatedconn = this.gates[index];\r\n\r\n this.ungate(gatedconn);\r\n break;\r\n case mutation.ADD_BACK_CONN:\r\n // Create an array of all uncreated (backfed) connections\r\n var available = [];\r\n for (i = this.input; i < this.nodes.length; i++) {\r\n let node1 = this.nodes[i];\r\n for (j = this.input; j < i; j++) {\r\n let node2 = this.nodes[j];\r\n if (!node1.isProjectingTo(node2)) available.push([node1, node2]);\r\n }\r\n }\r\n\r\n if (available.length === 0) {\r\n if (config.warnings) console.warn('No more connections to be made!');\r\n break;\r\n }\r\n\r\n var pair = available[Math.floor(Math.random() * available.length)];\r\n this.connect(pair[0], pair[1]);\r\n break;\r\n case mutation.SUB_BACK_CONN:\r\n // List of possible connections that can be removed\r\n var possible = [];\r\n\r\n for (i = 0; i < this.connections.length; i++) {\r\n let conn = this.connections[i];\r\n // Check if it is not disabling a node\r\n if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) {\r\n possible.push(conn);\r\n }\r\n }\r\n\r\n if (possible.length === 0) {\r\n if (config.warnings) console.warn('No connections to remove!');\r\n break;\r\n }\r\n\r\n var randomConn = possible[Math.floor(Math.random() * possible.length)];\r\n this.disconnect(randomConn.from, randomConn.to);\r\n break;\r\n case mutation.SWAP_NODES:\r\n // Has no effect on input node, so they are excluded\r\n if ((method.mutateOutput && this.nodes.length - this.input < 2) ||\r\n (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) {\r\n if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function');\r\n break;\r\n }\r\n\r\n var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input);\r\n var node1 = this.nodes[index];\r\n index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input);\r\n var node2 = this.nodes[index];\r\n\r\n var biasTemp = node1.bias;\r\n var squashTemp = node1.squash;\r\n\r\n node1.bias = node2.bias;\r\n node1.squash = node2.squash;\r\n node2.bias = biasTemp;\r\n node2.squash = squashTemp;\r\n break;\r\n }\r\n },\r\n\r\n /**\r\n * Train the given set to this network\r\n */\r\n train: function (set, options) {\r\n if (set[0].input.length !== this.input || set[0].output.length !== this.output) {\r\n throw new Error('Dataset input/output size should be same as network input/output size!');\r\n }\r\n\r\n options = options || {};\r\n\r\n // Warning messages\r\n if (typeof options.rate === 'undefined') {\r\n if (config.warnings) console.warn('Using default learning rate, please define a rate!');\r\n }\r\n if (typeof options.iterations === 'undefined') {\r\n if (config.warnings) console.warn('No target iterations given, running until error is reached!');\r\n }\r\n\r\n // Read the options\r\n var targetError = options.error || 0.05;\r\n var cost = options.cost || methods.cost.MSE;\r\n var baseRate = options.rate || 0.3;\r\n var dropout = options.dropout || 0;\r\n var momentum = options.momentum || 0;\r\n var batchSize = options.batchSize || 1; // online learning\r\n var ratePolicy = options.ratePolicy || methods.rate.FIXED();\r\n\r\n var start = Date.now();\r\n\r\n if (batchSize > set.length) {\r\n throw new Error('Batch size must be smaller or equal to dataset length!');\r\n } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') {\r\n throw new Error('At least one of the following options must be specified: error, iterations');\r\n } else if (typeof options.error === 'undefined') {\r\n targetError = -1; // run until iterations\r\n } else if (typeof options.iterations === 'undefined') {\r\n options.iterations = 0; // run until target error\r\n }\r\n\r\n // Save to network\r\n this.dropout = dropout;\r\n\r\n if (options.crossValidate) {\r\n let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length);\r\n var trainSet = set.slice(0, numTrain);\r\n var testSet = set.slice(numTrain);\r\n }\r\n\r\n // Loops the training process\r\n var currentRate = baseRate;\r\n var iteration = 0;\r\n var error = 1;\r\n\r\n var i, j, x;\r\n while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) {\r\n if (options.crossValidate && error <= options.crossValidate.testError) break;\r\n\r\n iteration++;\r\n\r\n // Update the rate\r\n currentRate = ratePolicy(baseRate, iteration);\r\n\r\n // Checks if cross validation is enabled\r\n if (options.crossValidate) {\r\n this._trainSet(trainSet, batchSize, currentRate, momentum, cost);\r\n if (options.clear) this.clear();\r\n error = this.test(testSet, cost).error;\r\n if (options.clear) this.clear();\r\n } else {\r\n error = this._trainSet(set, batchSize, currentRate, momentum, cost);\r\n if (options.clear) this.clear();\r\n }\r\n\r\n // Checks for options such as scheduled logs and shuffling\r\n if (options.shuffle) {\r\n for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x);\r\n }\r\n\r\n if (options.log && iteration % options.log === 0) {\r\n console.log('iteration', iteration, 'error', error, 'rate', currentRate);\r\n }\r\n\r\n if (options.schedule && iteration % options.schedule.iterations === 0) {\r\n options.schedule.function({ error: error, iteration: iteration });\r\n }\r\n }\r\n\r\n if (options.clear) this.clear();\r\n\r\n if (dropout) {\r\n for (i = 0; i < this.nodes.length; i++) {\r\n if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') {\r\n this.nodes[i].mask = 1 - this.dropout;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n error: error,\r\n iterations: iteration,\r\n time: Date.now() - start\r\n };\r\n },\r\n\r\n /**\r\n * Performs one training epoch and returns the error\r\n * private function used in this.train\r\n */\r\n _trainSet: function (set, batchSize, currentRate, momentum, costFunction) {\r\n var errorSum = 0;\r\n for (var i = 0; i < set.length; i++) {\r\n var input = set[i].input;\r\n var target = set[i].output;\r\n\r\n var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length);\r\n\r\n var output = this.activate(input, true);\r\n this.propagate(currentRate, momentum, update, target);\r\n\r\n errorSum += costFunction(target, output);\r\n }\r\n return errorSum / set.length;\r\n },\r\n\r\n /**\r\n * Tests a set and returns the error and elapsed time\r\n */\r\n test: function (set, cost = methods.cost.MSE) {\r\n // Check if dropout is enabled, set correct mask\r\n var i;\r\n if (this.dropout) {\r\n for (i = 0; i < this.nodes.length; i++) {\r\n if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') {\r\n this.nodes[i].mask = 1 - this.dropout;\r\n }\r\n }\r\n }\r\n\r\n var error = 0;\r\n var start = Date.now();\r\n\r\n for (i = 0; i < set.length; i++) {\r\n let input = set[i].input;\r\n let target = set[i].output;\r\n let output = this.noTraceActivate(input);\r\n error += cost(target, output);\r\n }\r\n\r\n error /= set.length;\r\n\r\n var results = {\r\n error: error,\r\n time: Date.now() - start\r\n };\r\n\r\n return results;\r\n },\r\n\r\n /**\r\n * Creates a json that can be used to create a graph with d3 and webcola\r\n */\r\n graph: function (width, height) {\r\n var input = 0;\r\n var output = 0;\r\n\r\n var json = {\r\n nodes: [],\r\n links: [],\r\n constraints: [{\r\n type: 'alignment',\r\n axis: 'x',\r\n offsets: []\r\n }, {\r\n type: 'alignment',\r\n axis: 'y',\r\n offsets: []\r\n }]\r\n };\r\n\r\n var i;\r\n for (i = 0; i < this.nodes.length; i++) {\r\n var node = this.nodes[i];\r\n\r\n if (node.type === 'input') {\r\n if (this.input === 1) {\r\n json.constraints[0].offsets.push({\r\n node: i,\r\n offset: 0\r\n });\r\n } else {\r\n json.constraints[0].offsets.push({\r\n node: i,\r\n offset: 0.8 * width / (this.input - 1) * input++\r\n });\r\n }\r\n json.constraints[1].offsets.push({\r\n node: i,\r\n offset: 0\r\n });\r\n } else if (node.type === 'output') {\r\n if (this.output === 1) {\r\n json.constraints[0].offsets.push({\r\n node: i,\r\n offset: 0\r\n });\r\n } else {\r\n json.constraints[0].offsets.push({\r\n node: i,\r\n offset: 0.8 * width / (this.output - 1) * output++\r\n });\r\n }\r\n json.constraints[1].offsets.push({\r\n node: i,\r\n offset: -0.8 * height\r\n });\r\n }\r\n\r\n json.nodes.push({\r\n id: i,\r\n name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(),\r\n activation: node.activation,\r\n bias: node.bias\r\n });\r\n }\r\n\r\n var connections = this.connections.concat(this.selfconns);\r\n for (i = 0; i < connections.length; i++) {\r\n var connection = connections[i];\r\n if (connection.gater == null) {\r\n json.links.push({\r\n source: this.nodes.indexOf(connection.from),\r\n target: this.nodes.indexOf(connection.to),\r\n weight: connection.weight\r\n });\r\n } else {\r\n // Add a gater 'node'\r\n var index = json.nodes.length;\r\n json.nodes.push({\r\n id: index,\r\n activation: connection.gater.activation,\r\n name: 'GATE'\r\n });\r\n json.links.push({\r\n source: this.nodes.indexOf(connection.from),\r\n target: index,\r\n weight: 1 / 2 * connection.weight\r\n });\r\n json.links.push({\r\n source: index,\r\n target: this.nodes.indexOf(connection.to),\r\n weight: 1 / 2 * connection.weight\r\n });\r\n json.links.push({\r\n source: this.nodes.indexOf(connection.gater),\r\n target: index,\r\n weight: connection.gater.activation,\r\n gate: true\r\n });\r\n }\r\n }\r\n\r\n return json;\r\n },\r\n\r\n /**\r\n * Convert the network to a json object\r\n */\r\n toJSON: function () {\r\n var json = {\r\n nodes: [],\r\n connections: [],\r\n input: this.input,\r\n output: this.output,\r\n dropout: this.dropout\r\n };\r\n\r\n // So we don't have to use expensive .indexOf()\r\n var i;\r\n for (i = 0; i < this.nodes.length; i++) {\r\n this.nodes[i].index = i;\r\n }\r\n\r\n for (i = 0; i < this.nodes.length; i++) {\r\n let node = this.nodes[i];\r\n let tojson = node.toJSON();\r\n tojson.index = i;\r\n json.nodes.push(tojson);\r\n\r\n if (node.connections.self.weight !== 0) {\r\n let tojson = node.connections.self.toJSON();\r\n tojson.from = i;\r\n tojson.to = i;\r\n\r\n tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null;\r\n json.connections.push(tojson);\r\n }\r\n }\r\n\r\n for (i = 0; i < this.connections.length; i++) {\r\n let conn = this.connections[i];\r\n let tojson = conn.toJSON();\r\n tojson.from = conn.from.index;\r\n tojson.to = conn.to.index;\r\n\r\n tojson.gater = conn.gater != null ? conn.gater.index : null;\r\n\r\n json.connections.push(tojson);\r\n }\r\n\r\n return json;\r\n },\r\n\r\n /**\r\n * Sets the value of a property for every node in this network\r\n */\r\n set: function (values) {\r\n for (var i = 0; i < this.nodes.length; i++) {\r\n this.nodes[i].bias = values.bias || this.nodes[i].bias;\r\n this.nodes[i].squash = values.squash || this.nodes[i].squash;\r\n }\r\n },\r\n\r\n /**\r\n * Evolves the network to reach a lower error on a dataset\r\n */\r\n evolve: async function (set, options) {\r\n if (set[0].input.length !== this.input || set[0].output.length !== this.output) {\r\n throw new Error('Dataset input/output size should be same as network input/output size!');\r\n }\r\n\r\n // Read the options\r\n options = options || {};\r\n var targetError = typeof options.error !== 'undefined' ? options.error : 0.05;\r\n var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001;\r\n var cost = options.cost || methods.cost.MSE;\r\n var amount = options.amount || 1;\r\n\r\n var threads = options.threads;\r\n if (typeof threads === 'undefined') {\r\n if (typeof window === 'undefined') { // Node.js\r\n threads = require('os').cpus().length;\r\n } else { // Browser\r\n threads = navigator.hardwareConcurrency;\r\n }\r\n }\r\n\r\n var start = Date.now();\r\n\r\n if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') {\r\n throw new Error('At least one of the following options must be specified: error, iterations');\r\n } else if (typeof options.error === 'undefined') {\r\n targetError = -1; // run until iterations\r\n } else if (typeof options.iterations === 'undefined') {\r\n options.iterations = 0; // run until target error\r\n }\r\n\r\n var fitnessFunction;\r\n if (threads === 1) {\r\n // Create the fitness function\r\n fitnessFunction = function (genome) {\r\n var score = 0;\r\n for (var i = 0; i < amount; i++) {\r\n score -= genome.test(set, cost).error;\r\n }\r\n\r\n score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth;\r\n score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection\r\n\r\n return score / amount;\r\n };\r\n } else {\r\n // Serialize the dataset\r\n var converted = multi.serializeDataSet(set);\r\n\r\n // Create workers, send datasets\r\n var workers = [];\r\n if (typeof window === 'undefined') {\r\n for (var i = 0; i < threads; i++) {\r\n workers.push(new multi.workers.node.TestWorker(converted, cost));\r\n }\r\n } else {\r\n for (var i = 0; i < threads; i++) {\r\n workers.push(new multi.workers.browser.TestWorker(converted, cost));\r\n }\r\n }\r\n\r\n fitnessFunction = function (population) {\r\n return new Promise((resolve, reject) => {\r\n // Create a queue\r\n var queue = population.slice();\r\n var done = 0;\r\n\r\n // Start worker function\r\n var startWorker = function (worker) {\r\n if (!queue.length) {\r\n if (++done === threads) resolve();\r\n return;\r\n }\r\n\r\n var genome = queue.shift();\r\n\r\n worker.evaluate(genome).then(function (result) {\r\n genome.score = -result;\r\n genome.score -= (genome.nodes.length - genome.input - genome.output +\r\n genome.connections.length + genome.gates.length) * growth;\r\n genome.score = isNaN(parseFloat(result)) ? -Infinity : genome.score;\r\n startWorker(worker);\r\n });\r\n };\r\n\r\n for (var i = 0; i < workers.length; i++) {\r\n startWorker(workers[i]);\r\n }\r\n });\r\n };\r\n\r\n options.fitnessPopulation = true;\r\n }\r\n\r\n // Intialise the NEAT instance\r\n options.network = this;\r\n var neat = new Neat(this.input, this.output, fitnessFunction, options);\r\n\r\n var error = -Infinity;\r\n var bestFitness = -Infinity;\r\n var bestGenome;\r\n\r\n while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) {\r\n let fittest = await neat.evolve();\r\n let fitness = fittest.score;\r\n error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth;\r\n\r\n if (fitness > bestFitness) {\r\n bestFitness = fitness;\r\n bestGenome = fittest;\r\n }\r\n\r\n if (options.log && neat.generation % options.log === 0) {\r\n console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error);\r\n }\r\n\r\n if (options.schedule && neat.generation % options.schedule.iterations === 0) {\r\n options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation });\r\n }\r\n }\r\n\r\n if (threads > 1) {\r\n for (var i = 0; i < workers.length; i++) workers[i].terminate();\r\n }\r\n\r\n if (typeof bestGenome !== 'undefined') {\r\n this.nodes = bestGenome.nodes;\r\n this.connections = bestGenome.connections;\r\n this.selfconns = bestGenome.selfconns;\r\n this.gates = bestGenome.gates;\r\n\r\n if (options.clear) this.clear();\r\n }\r\n\r\n return {\r\n error: -error,\r\n iterations: neat.generation,\r\n time: Date.now() - start\r\n };\r\n },\r\n\r\n /**\r\n * Creates a standalone function of the network which can be run without the\r\n * need of a library\r\n */\r\n standalone: function () {\r\n var present = [];\r\n var activations = [];\r\n var states = [];\r\n var lines = [];\r\n var functions = [];\r\n\r\n var i;\r\n for (i = 0; i < this.input; i++) {\r\n var node = this.nodes[i];\r\n activations.push(node.activation);\r\n states.push(node.state);\r\n }\r\n\r\n lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];');\r\n\r\n // So we don't have to use expensive .indexOf()\r\n for (i = 0; i < this.nodes.length; i++) {\r\n this.nodes[i].index = i;\r\n }\r\n\r\n for (i = this.input; i < this.nodes.length; i++) {\r\n let node = this.nodes[i];\r\n activations.push(node.activation);\r\n states.push(node.state);\r\n\r\n var functionIndex = present.indexOf(node.squash.name);\r\n\r\n if (functionIndex === -1) {\r\n functionIndex = present.length;\r\n present.push(node.squash.name);\r\n functions.push(node.squash.toString());\r\n }\r\n\r\n var incoming = [];\r\n for (var j = 0; j < node.connections.in.length; j++) {\r\n var conn = node.connections.in[j];\r\n var computation = `A[${conn.from.index}] * ${conn.weight}`;\r\n\r\n if (conn.gater != null) {\r\n computation += ` * A[${conn.gater.index}]`;\r\n }\r\n\r\n incoming.push(computation);\r\n }\r\n\r\n if (node.connections.self.weight) {\r\n let conn = node.connections.self;\r\n let computation = `S[${i}] * ${conn.weight}`;\r\n\r\n if (conn.gater != null) {\r\n computation += ` * A[${conn.gater.index}]`;\r\n }\r\n\r\n incoming.push(computation);\r\n }\r\n\r\n var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`;\r\n var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`;\r\n lines.push(line1);\r\n lines.push(line2);\r\n }\r\n\r\n var output = [];\r\n for (i = this.nodes.length - this.output; i < this.nodes.length; i++) {\r\n output.push(`A[${i}]`);\r\n }\r\n\r\n output = `return [${output.join(',')}];`;\r\n lines.push(output);\r\n\r\n var total = '';\r\n total += `var F = [${functions.toString()}];\\r\\n`;\r\n total += `var A = [${activations.toString()}];\\r\\n`;\r\n total += `var S = [${states.toString()}];\\r\\n`;\r\n total += `function activate(input){\\r\\n${lines.join('\\r\\n')}\\r\\n}`;\r\n\r\n return total;\r\n },\r\n\r\n /**\r\n * Serialize to send to workers efficiently\r\n */\r\n serialize: function () {\r\n var activations = [];\r\n var states = [];\r\n var conns = [];\r\n var squashes = [\r\n 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID',\r\n 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH',\r\n 'ABSOLUTE', 'INVERSE', 'SELU'\r\n ];\r\n\r\n conns.push(this.input);\r\n conns.push(this.output);\r\n\r\n var i;\r\n for (i = 0; i < this.nodes.length; i++) {\r\n let node = this.nodes[i];\r\n node.index = i;\r\n activations.push(node.activation);\r\n states.push(node.state);\r\n }\r\n\r\n for (i = this.input; i < this.nodes.length; i++) {\r\n let node = this.nodes[i];\r\n conns.push(node.index);\r\n conns.push(node.bias);\r\n conns.push(squashes.indexOf(node.squash.name));\r\n\r\n conns.push(node.connections.self.weight);\r\n conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index);\r\n\r\n for (var j = 0; j < node.connections.in.length; j++) {\r\n let conn = node.connections.in[j];\r\n\r\n conns.push(conn.from.index);\r\n conns.push(conn.weight);\r\n conns.push(conn.gater == null ? -1 : conn.gater.index);\r\n }\r\n\r\n conns.push(-2); // stop token -> next node\r\n }\r\n\r\n return [activations, states, conns];\r\n }\r\n};\r\n\r\n/**\r\n * Convert a json object to a network\r\n */\r\nNetwork.fromJSON = function (json) {\r\n var network = new Network(json.input, json.output);\r\n network.dropout = json.dropout;\r\n network.nodes = [];\r\n network.connections = [];\r\n\r\n var i;\r\n for (i = 0; i < json.nodes.length; i++) {\r\n network.nodes.push(Node.fromJSON(json.nodes[i]));\r\n }\r\n\r\n for (i = 0; i < json.connections.length; i++) {\r\n var conn = json.connections[i];\r\n\r\n var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0];\r\n connection.weight = conn.weight;\r\n\r\n if (conn.gater != null) {\r\n network.gate(network.nodes[conn.gater], connection);\r\n }\r\n }\r\n\r\n return network;\r\n};\r\n\r\n/**\r\n * Merge two networks into one\r\n */\r\nNetwork.merge = function (network1, network2) {\r\n // Create a copy of the networks\r\n network1 = Network.fromJSON(network1.toJSON());\r\n network2 = Network.fromJSON(network2.toJSON());\r\n\r\n // Check if output and input size are the same\r\n if (network1.output !== network2.input) {\r\n throw new Error('Output size of network1 should be the same as the input size of network2!');\r\n }\r\n\r\n // Redirect all connections from network2 input from network1 output\r\n var i;\r\n for (i = 0; i < network2.connections.length; i++) {\r\n let conn = network2.connections[i];\r\n if (conn.from.type === 'input') {\r\n let index = network2.nodes.indexOf(conn.from);\r\n\r\n // redirect\r\n conn.from = network1.nodes[network1.nodes.length - 1 - index];\r\n }\r\n }\r\n\r\n // Delete input nodes of network2\r\n for (i = network2.input - 1; i >= 0; i--) {\r\n network2.nodes.splice(i, 1);\r\n }\r\n\r\n // Change the node type of network1's output nodes (now hidden)\r\n for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) {\r\n network1.nodes[i].type = 'hidden';\r\n }\r\n\r\n // Create one network from both networks\r\n network1.connections = network1.connections.concat(network2.connections);\r\n network1.nodes = network1.nodes.concat(network2.nodes);\r\n\r\n return network1;\r\n};\r\n\r\n/**\r\n * Create an offspring from two parent networks\r\n */\r\nNetwork.crossOver = function (network1, network2, equal) {\r\n if (network1.input !== network2.input || network1.output !== network2.output) {\r\n throw new Error(\"Networks don't have the same input/output size!\");\r\n }\r\n\r\n // Initialise offspring\r\n var offspring = new Network(network1.input, network1.output);\r\n offspring.connections = [];\r\n offspring.nodes = [];\r\n\r\n // Save scores and create a copy\r\n var score1 = network1.score || 0;\r\n var score2 = network2.score || 0;\r\n\r\n // Determine offspring node size\r\n var size;\r\n if (equal || score1 === score2) {\r\n let max = Math.max(network1.nodes.length, network2.nodes.length);\r\n let min = Math.min(network1.nodes.length, network2.nodes.length);\r\n size = Math.floor(Math.random() * (max - min + 1) + min);\r\n } else if (score1 > score2) {\r\n size = network1.nodes.length;\r\n } else {\r\n size = network2.nodes.length;\r\n }\r\n\r\n // Rename some variables for easier reading\r\n var outputSize = network1.output;\r\n\r\n // Set indexes so we don't need indexOf\r\n var i;\r\n for (i = 0; i < network1.nodes.length; i++) {\r\n network1.nodes[i].index = i;\r\n }\r\n\r\n for (i = 0; i < network2.nodes.length; i++) {\r\n network2.nodes[i].index = i;\r\n }\r\n\r\n // Assign nodes from parents to offspring\r\n for (i = 0; i < size; i++) {\r\n // Determine if an output node is needed\r\n var node;\r\n if (i < size - outputSize) {\r\n let random = Math.random();\r\n node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i];\r\n let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i];\r\n\r\n if (typeof node === 'undefined' || node.type === 'output') {\r\n node = other;\r\n }\r\n } else {\r\n if (Math.random() >= 0.5) {\r\n node = network1.nodes[network1.nodes.length + i - size];\r\n } else {\r\n node = network2.nodes[network2.nodes.length + i - size];\r\n }\r\n }\r\n\r\n var newNode = new Node();\r\n newNode.bias = node.bias;\r\n newNode.squash = node.squash;\r\n newNode.type = node.type;\r\n\r\n offspring.nodes.push(newNode);\r\n }\r\n\r\n // Create arrays of connection genes\r\n var n1conns = {};\r\n var n2conns = {};\r\n\r\n // Normal connections\r\n for (i = 0; i < network1.connections.length; i++) {\r\n let conn = network1.connections[i];\r\n let data = {\r\n weight: conn.weight,\r\n from: conn.from.index,\r\n to: conn.to.index,\r\n gater: conn.gater != null ? conn.gater.index : -1\r\n };\r\n n1conns[Connection.innovationID(data.from, data.to)] = data;\r\n }\r\n\r\n // Selfconnections\r\n for (i = 0; i < network1.selfconns.length; i++) {\r\n let conn = network1.selfconns[i];\r\n let data = {\r\n weight: conn.weight,\r\n from: conn.from.index,\r\n to: conn.to.index,\r\n gater: conn.gater != null ? conn.gater.index : -1\r\n };\r\n n1conns[Connection.innovationID(data.from, data.to)] = data;\r\n }\r\n\r\n // Normal connections\r\n for (i = 0; i < network2.connections.length; i++) {\r\n let conn = network2.connections[i];\r\n let data = {\r\n weight: conn.weight,\r\n from: conn.from.index,\r\n to: conn.to.index,\r\n gater: conn.gater != null ? conn.gater.index : -1\r\n };\r\n n2conns[Connection.innovationID(data.from, data.to)] = data;\r\n }\r\n\r\n // Selfconnections\r\n for (i = 0; i < network2.selfconns.length; i++) {\r\n let conn = network2.selfconns[i];\r\n let data = {\r\n weight: conn.weight,\r\n from: conn.from.index,\r\n to: conn.to.index,\r\n gater: conn.gater != null ? conn.gater.index : -1\r\n };\r\n n2conns[Connection.innovationID(data.from, data.to)] = data;\r\n }\r\n\r\n // Split common conn genes from disjoint or excess conn genes\r\n var connections = [];\r\n var keys1 = Object.keys(n1conns);\r\n var keys2 = Object.keys(n2conns);\r\n for (i = keys1.length - 1; i >= 0; i--) {\r\n // Common gene\r\n if (typeof n2conns[keys1[i]] !== 'undefined') {\r\n let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]];\r\n connections.push(conn);\r\n\r\n // Because deleting is expensive, just set it to some value\r\n n2conns[keys1[i]] = undefined;\r\n } else if (score1 >= score2 || equal) {\r\n connections.push(n1conns[keys1[i]]);\r\n }\r\n }\r\n\r\n // Excess/disjoint gene\r\n if (score2 >= score1 || equal) {\r\n for (i = 0; i < keys2.length; i++) {\r\n if (typeof n2conns[keys2[i]] !== 'undefined') {\r\n connections.push(n2conns[keys2[i]]);\r\n }\r\n }\r\n }\r\n\r\n // Add common conn genes uniformly\r\n for (i = 0; i < connections.length; i++) {\r\n let connData = connections[i];\r\n if (connData.to < size && connData.from < size) {\r\n let from = offspring.nodes[connData.from];\r\n let to = offspring.nodes[connData.to];\r\n let conn = offspring.connect(from, to)[0];\r\n\r\n conn.weight = connData.weight;\r\n\r\n if (connData.gater !== -1 && connData.gater < size) {\r\n offspring.gate(offspring.nodes[connData.gater], conn);\r\n }\r\n }\r\n }\r\n\r\n return offspring;\r\n};\r\n", "/* Export */\r\nmodule.exports = Layer;\r\n\r\n/* Import */\r\nvar methods = require('../methods/methods');\r\nvar Group = require('./group');\r\nvar Node = require('./node');\r\n\r\n/*******************************************************************************\r\n Group\r\n*******************************************************************************/\r\n\r\nfunction Layer () {\r\n this.output = null;\r\n\r\n this.nodes = [];\r\n this.connections = { in: [],\r\n out: [],\r\n self: []\r\n };\r\n}\r\n\r\nLayer.prototype = {\r\n /**\r\n * Activates all the nodes in the group\r\n */\r\n activate: function (value) {\r\n var values = [];\r\n\r\n if (typeof value !== 'undefined' && value.length !== this.nodes.length) {\r\n throw new Error('Array with values should be same as the amount of nodes!');\r\n }\r\n\r\n for (var i = 0; i < this.nodes.length; i++) {\r\n var activation;\r\n if (typeof value === 'undefined') {\r\n activation = this.nodes[i].activate();\r\n } else {\r\n activation = this.nodes[i].activate(value[i]);\r\n }\r\n\r\n values.push(activation);\r\n }\r\n\r\n return values;\r\n },\r\n\r\n /**\r\n * Propagates all the node in the group\r\n */\r\n propagate: function (rate, momentum, target) {\r\n if (typeof target !== 'undefined' && target.length !== this.nodes.length) {\r\n throw new Error('Array with values should be same as the amount of nodes!');\r\n }\r\n\r\n for (var i = this.nodes.length - 1; i >= 0; i--) {\r\n if (typeof target === 'undefined') {\r\n this.nodes[i].propagate(rate, momentum, true);\r\n } else {\r\n this.nodes[i].propagate(rate, momentum, true, target[i]);\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * Connects the nodes in this group to nodes in another group or just a node\r\n */\r\n connect: function (target, method, weight) {\r\n var connections;\r\n if (target instanceof Group || target instanceof Node) {\r\n connections = this.output.connect(target, method, weight);\r\n } else if (target instanceof Layer) {\r\n connections = target.input(this, method, weight);\r\n }\r\n\r\n return connections;\r\n },\r\n\r\n /**\r\n * Make nodes from this group gate the given connection(s)\r\n */\r\n gate: function (connections, method) {\r\n this.output.gate(connections, method);\r\n },\r\n\r\n /**\r\n * Sets the value of a property for every node\r\n */\r\n set: function (values) {\r\n for (var i = 0; i < this.nodes.length; i++) {\r\n var node = this.nodes[i];\r\n\r\n if (node instanceof Node) {\r\n if (typeof values.bias !== 'undefined') {\r\n node.bias = values.bias;\r\n }\r\n\r\n node.squash = values.squash || node.squash;\r\n node.type = values.type || node.type;\r\n } else if (node instanceof Group) {\r\n node.set(values);\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * Disconnects all nodes from this group from another given group/node\r\n */\r\n disconnect: function (target, twosided) {\r\n twosided = twosided || false;\r\n\r\n // In the future, disconnect will return a connection so indexOf can be used\r\n var i, j, k;\r\n if (target instanceof Group) {\r\n for (i = 0; i < this.nodes.length; i++) {\r\n for (j = 0; j < target.nodes.length; j++) {\r\n this.nodes[i].disconnect(target.nodes[j], twosided);\r\n\r\n for (k = this.connections.out.length - 1; k >= 0; k--) {\r\n let conn = this.connections.out[k];\r\n\r\n if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) {\r\n this.connections.out.splice(k, 1);\r\n break;\r\n }\r\n }\r\n\r\n if (twosided) {\r\n for (k = this.connections.in.length - 1; k >= 0; k--) {\r\n let conn = this.connections.in[k];\r\n\r\n if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) {\r\n this.connections.in.splice(k, 1);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } else if (target instanceof Node) {\r\n for (i = 0; i < this.nodes.length; i++) {\r\n this.nodes[i].disconnect(target, twosided);\r\n\r\n for (j = this.connections.out.length - 1; j >= 0; j--) {\r\n let conn = this.connections.out[j];\r\n\r\n if (conn.from === this.nodes[i] && conn.to === target) {\r\n this.connections.out.splice(j, 1);\r\n break;\r\n }\r\n }\r\n\r\n if (twosided) {\r\n for (k = this.connections.in.length - 1; k >= 0; k--) {\r\n let conn = this.connections.in[k];\r\n\r\n if (conn.from === target && conn.to === this.nodes[i]) {\r\n this.connections.in.splice(k, 1);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * Clear the context of this group\r\n */\r\n clear: function () {\r\n for (var i = 0; i < this.nodes.length; i++) {\r\n this.nodes[i].clear();\r\n }\r\n }\r\n};\r\n\r\nLayer.Dense = function (size) {\r\n // Create the layer\r\n var layer = new Layer();\r\n\r\n // Init required nodes (in activation order)\r\n var block = new Group(size);\r\n\r\n layer.nodes.push(block);\r\n layer.output = block;\r\n\r\n layer.input = function (from, method, weight) {\r\n if (from instanceof Layer) from = from.output;\r\n method = method || methods.connection.ALL_TO_ALL;\r\n return from.connect(block, method, weight);\r\n };\r\n\r\n return layer;\r\n};\r\n\r\nLayer.LSTM = function (size) {\r\n // Create the layer\r\n var layer = new Layer();\r\n\r\n // Init required nodes (in activation order)\r\n var inputGate = new Group(size);\r\n var forgetGate = new Group(size);\r\n var memoryCell = new Group(size);\r\n var outputGate = new Group(size);\r\n var outputBlock = new Group(size);\r\n\r\n inputGate.set({\r\n bias: 1\r\n });\r\n forgetGate.set({\r\n bias: 1\r\n });\r\n outputGate.set({\r\n bias: 1\r\n });\r\n\r\n // Set up internal connections\r\n memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL);\r\n memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL);\r\n memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL);\r\n var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE);\r\n var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL);\r\n\r\n // Set up gates\r\n forgetGate.gate(forget, methods.gating.SELF);\r\n outputGate.gate(output, methods.gating.OUTPUT);\r\n\r\n // Add to nodes array\r\n layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock];\r\n\r\n // Define output\r\n layer.output = outputBlock;\r\n\r\n layer.input = function (from, method, weight) {\r\n if (from instanceof Layer) from = from.output;\r\n method = method || methods.connection.ALL_TO_ALL;\r\n var connections = [];\r\n\r\n var input = from.connect(memoryCell, method, weight);\r\n connections = connections.concat(input);\r\n\r\n connections = connections.concat(from.connect(inputGate, method, weight));\r\n connections = connections.concat(from.connect(outputGate, method, weight));\r\n connections = connections.concat(from.connect(forgetGate, method, weight));\r\n\r\n inputGate.gate(input, methods.gating.INPUT);\r\n\r\n return connections;\r\n };\r\n\r\n return layer;\r\n};\r\n\r\nLayer.GRU = function (size) {\r\n // Create the layer\r\n var layer = new Layer();\r\n\r\n var updateGate = new Group(size);\r\n var inverseUpdateGate = new Group(size);\r\n var resetGate = new Group(size);\r\n var memoryCell = new Group(size);\r\n var output = new Group(size);\r\n var previousOutput = new Group(size);\r\n\r\n previousOutput.set({\r\n bias: 0,\r\n squash: methods.activation.IDENTITY,\r\n type: 'constant'\r\n });\r\n memoryCell.set({\r\n squash: methods.activation.TANH\r\n });\r\n inverseUpdateGate.set({\r\n bias: 0,\r\n squash: methods.activation.INVERSE,\r\n type: 'constant'\r\n });\r\n updateGate.set({\r\n bias: 1\r\n });\r\n resetGate.set({\r\n bias: 0\r\n });\r\n\r\n // Update gate calculation\r\n previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL);\r\n\r\n // Inverse update gate calculation\r\n updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1);\r\n\r\n // Reset gate calculation\r\n previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL);\r\n\r\n // Memory calculation\r\n var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL);\r\n\r\n resetGate.gate(reset, methods.gating.OUTPUT); // gate\r\n\r\n // Output calculation\r\n var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL);\r\n var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL);\r\n\r\n updateGate.gate(update1, methods.gating.OUTPUT);\r\n inverseUpdateGate.gate(update2, methods.gating.OUTPUT);\r\n\r\n // Previous output calculation\r\n output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1);\r\n\r\n // Add to nodes array\r\n layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput];\r\n\r\n layer.output = output;\r\n\r\n layer.input = function (from, method, weight) {\r\n if (from instanceof Layer) from = from.output;\r\n method = method || methods.connection.ALL_TO_ALL;\r\n var connections = [];\r\n\r\n connections = connections.concat(from.connect(updateGate, method, weight));\r\n connections = connections.concat(from.connect(resetGate, method, weight));\r\n connections = connections.concat(from.connect(memoryCell, method, weight));\r\n\r\n return connections;\r\n };\r\n\r\n return layer;\r\n};\r\n\r\nLayer.Memory = function (size, memory) {\r\n // Create the layer\r\n var layer = new Layer();\r\n // Because the output can only be one group, we have to put the nodes all in \u00F3ne group\r\n\r\n var previous = null;\r\n var i;\r\n for (i = 0; i < memory; i++) {\r\n var block = new Group(size);\r\n\r\n block.set({\r\n squash: methods.activation.IDENTITY,\r\n bias: 0,\r\n type: 'constant'\r\n });\r\n\r\n if (previous != null) {\r\n previous.connect(block, methods.connection.ONE_TO_ONE, 1);\r\n }\r\n\r\n layer.nodes.push(block);\r\n previous = block;\r\n }\r\n\r\n layer.nodes.reverse();\r\n\r\n for (i = 0; i < layer.nodes.length; i++) {\r\n layer.nodes[i].nodes.reverse();\r\n }\r\n\r\n // Because output can only be \u00F3ne group, fit all memory nodes in \u00F3ne group\r\n var outputGroup = new Group(0);\r\n for (var group in layer.nodes) {\r\n outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes);\r\n }\r\n layer.output = outputGroup;\r\n\r\n layer.input = function (from, method, weight) {\r\n if (from instanceof Layer) from = from.output;\r\n method = method || methods.connection.ALL_TO_ALL;\r\n\r\n if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) {\r\n throw new Error('Previous layer size must be same as memory size');\r\n }\r\n\r\n return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1);\r\n };\r\n\r\n return layer;\r\n};\r\n", "/* Export */\r\nmodule.exports = Group;\r\n\r\n/* Import */\r\nvar methods = require('../methods/methods');\r\nvar config = require('../config');\r\nvar Layer = require('./layer');\r\nvar Node = require('./node');\r\n\r\n/*******************************************************************************\r\n Group\r\n*******************************************************************************/\r\n\r\nfunction Group (size) {\r\n this.nodes = [];\r\n this.connections = {\r\n in: [],\r\n out: [],\r\n self: []\r\n };\r\n\r\n for (var i = 0; i < size; i++) {\r\n this.nodes.push(new Node());\r\n }\r\n}\r\n\r\nGroup.prototype = {\r\n /**\r\n * Activates all the nodes in the group\r\n */\r\n activate: function (value) {\r\n var values = [];\r\n\r\n if (typeof value !== 'undefined' && value.length !== this.nodes.length) {\r\n throw new Error('Array with values should be same as the amount of nodes!');\r\n }\r\n\r\n for (var i = 0; i < this.nodes.length; i++) {\r\n var activation;\r\n if (typeof value === 'undefined') {\r\n activation = this.nodes[i].activate();\r\n } else {\r\n activation = this.nodes[i].activate(value[i]);\r\n }\r\n\r\n values.push(activation);\r\n }\r\n\r\n return values;\r\n },\r\n\r\n /**\r\n * Propagates all the node in the group\r\n */\r\n propagate: function (rate, momentum, target) {\r\n if (typeof target !== 'undefined' && target.length !== this.nodes.length) {\r\n throw new Error('Array with values should be same as the amount of nodes!');\r\n }\r\n\r\n for (var i = this.nodes.length - 1; i >= 0; i--) {\r\n if (typeof target === 'undefined') {\r\n this.nodes[i].propagate(rate, momentum, true);\r\n } else {\r\n this.nodes[i].propagate(rate, momentum, true, target[i]);\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * Connects the nodes in this group to nodes in another group or just a node\r\n */\r\n connect: function (target, method, weight) {\r\n var connections = [];\r\n var i, j;\r\n if (target instanceof Group) {\r\n if (typeof method === 'undefined') {\r\n if (this !== target) {\r\n if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL');\r\n method = methods.connection.ALL_TO_ALL;\r\n } else {\r\n if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE');\r\n method = methods.connection.ONE_TO_ONE;\r\n }\r\n }\r\n if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) {\r\n for (i = 0; i < this.nodes.length; i++) {\r\n for (j = 0; j < target.nodes.length; j++) {\r\n if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue;\r\n let connection = this.nodes[i].connect(target.nodes[j], weight);\r\n this.connections.out.push(connection[0]);\r\n target.connections.in.push(connection[0]);\r\n connections.push(connection[0]);\r\n }\r\n }\r\n } else if (method === methods.connection.ONE_TO_ONE) {\r\n if (this.nodes.length !== target.nodes.length) {\r\n throw new Error('From and To group must be the same size!');\r\n }\r\n\r\n for (i = 0; i < this.nodes.length; i++) {\r\n let connection = this.nodes[i].connect(target.nodes[i], weight);\r\n this.connections.self.push(connection[0]);\r\n connections.push(connection[0]);\r\n }\r\n }\r\n } else if (target instanceof Layer) {\r\n connections = target.input(this, method, weight);\r\n } else if (target instanceof Node) {\r\n for (i = 0; i < this.nodes.length; i++) {\r\n let connection = this.nodes[i].connect(target, weight);\r\n this.connections.out.push(connection[0]);\r\n connections.push(connection[0]);\r\n }\r\n }\r\n\r\n return connections;\r\n },\r\n\r\n /**\r\n * Make nodes from this group gate the given connection(s)\r\n */\r\n gate: function (connections, method) {\r\n if (typeof method === 'undefined') {\r\n throw new Error('Please specify Gating.INPUT, Gating.OUTPUT');\r\n }\r\n\r\n if (!Array.isArray(connections)) {\r\n connections = [connections];\r\n }\r\n\r\n var nodes1 = [];\r\n var nodes2 = [];\r\n\r\n var i, j;\r\n for (i = 0; i < connections.length; i++) {\r\n var connection = connections[i];\r\n if (!nodes1.includes(connection.from)) nodes1.push(connection.from);\r\n if (!nodes2.includes(connection.to)) nodes2.push(connection.to);\r\n }\r\n\r\n switch (method) {\r\n case methods.gating.INPUT:\r\n for (i = 0; i < nodes2.length; i++) {\r\n let node = nodes2[i];\r\n let gater = this.nodes[i % this.nodes.length];\r\n\r\n for (j = 0; j < node.connections.in.length; j++) {\r\n let conn = node.connections.in[j];\r\n if (connections.includes(conn)) {\r\n gater.gate(conn);\r\n }\r\n }\r\n }\r\n break;\r\n case methods.gating.OUTPUT:\r\n for (i = 0; i < nodes1.length; i++) {\r\n let node = nodes1[i];\r\n let gater = this.nodes[i % this.nodes.length];\r\n\r\n for (j = 0; j < node.connections.out.length; j++) {\r\n let conn = node.connections.out[j];\r\n if (connections.includes(conn)) {\r\n gater.gate(conn);\r\n }\r\n }\r\n }\r\n break;\r\n case methods.gating.SELF:\r\n for (i = 0; i < nodes1.length; i++) {\r\n let node = nodes1[i];\r\n let gater = this.nodes[i % this.nodes.length];\r\n\r\n if (connections.includes(node.connections.self)) {\r\n gater.gate(node.connections.self);\r\n }\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * Sets the value of a property for every node\r\n */\r\n set: function (values) {\r\n for (var i = 0; i < this.nodes.length; i++) {\r\n if (typeof values.bias !== 'undefined') {\r\n this.nodes[i].bias = values.bias;\r\n }\r\n\r\n this.nodes[i].squash = values.squash || this.nodes[i].squash;\r\n this.nodes[i].type = values.type || this.nodes[i].type;\r\n }\r\n },\r\n\r\n /**\r\n * Disconnects all nodes from this group from another given group/node\r\n */\r\n disconnect: function (target, twosided) {\r\n twosided = twosided || false;\r\n\r\n // In the future, disconnect will return a connection so indexOf can be used\r\n var i, j, k;\r\n if (target instanceof Group) {\r\n for (i = 0; i < this.nodes.length; i++) {\r\n for (j = 0; j < target.nodes.length; j++) {\r\n this.nodes[i].disconnect(target.nodes[j], twosided);\r\n\r\n for (k = this.connections.out.length - 1; k >= 0; k--) {\r\n let conn = this.connections.out[k];\r\n\r\n if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) {\r\n this.connections.out.splice(k, 1);\r\n break;\r\n }\r\n }\r\n\r\n if (twosided) {\r\n for (k = this.connections.in.length - 1; k >= 0; k--) {\r\n let conn = this.connections.in[k];\r\n\r\n if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) {\r\n this.connections.in.splice(k, 1);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n } else if (target instanceof Node) {\r\n for (i = 0; i < this.nodes.length; i++) {\r\n this.nodes[i].disconnect(target, twosided);\r\n\r\n for (j = this.connections.out.length - 1; j >= 0; j--) {\r\n let conn = this.connections.out[j];\r\n\r\n if (conn.from === this.nodes[i] && conn.to === target) {\r\n this.connections.out.splice(j, 1);\r\n break;\r\n }\r\n }\r\n\r\n if (twosided) {\r\n for (j = this.connections.in.length - 1; j >= 0; j--) {\r\n var conn = this.connections.in[j];\r\n\r\n if (conn.from === target && conn.to === this.nodes[i]) {\r\n this.connections.in.splice(j, 1);\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n },\r\n\r\n /**\r\n * Clear the context of this group\r\n */\r\n clear: function () {\r\n for (var i = 0; i < this.nodes.length; i++) {\r\n this.nodes[i].clear();\r\n }\r\n }\r\n};\r\n", "/* Import */\r\nvar methods = require('../methods/methods');\r\nvar Network = require('./network');\r\nvar Group = require('./group');\r\nvar Layer = require('./layer');\r\nvar Node = require('./node');\r\n\r\n/*******************************************************************************\r\n architect\r\n*******************************************************************************/\r\n\r\nvar architect = {\r\n /**\r\n * Constructs a network from a given array of connected nodes\r\n */\r\n Construct: function (list) {\r\n // Create a network\r\n var network = new Network(0, 0);\r\n\r\n // Transform all groups into nodes\r\n var nodes = [];\r\n\r\n var i;\r\n for (i = 0; i < list.length; i++) {\r\n let j;\r\n if (list[i] instanceof Group) {\r\n for (j = 0; j < list[i].nodes.length; j++) {\r\n nodes.push(list[i].nodes[j]);\r\n }\r\n } else if (list[i] instanceof Layer) {\r\n for (j = 0; j < list[i].nodes.length; j++) {\r\n for (var k = 0; k < list[i].nodes[j].nodes.length; k++) {\r\n nodes.push(list[i].nodes[j].nodes[k]);\r\n }\r\n }\r\n } else if (list[i] instanceof Node) {\r\n nodes.push(list[i]);\r\n }\r\n }\r\n\r\n // Determine input and output nodes\r\n var inputs = [];\r\n var outputs = [];\r\n for (i = nodes.length - 1; i >= 0; i--) {\r\n if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) {\r\n nodes[i].type = 'output';\r\n network.output++;\r\n outputs.push(nodes[i]);\r\n nodes.splice(i, 1);\r\n } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) {\r\n nodes[i].type = 'input';\r\n network.input++;\r\n inputs.push(nodes[i]);\r\n nodes.splice(i, 1);\r\n }\r\n }\r\n\r\n // Input nodes are always first, output nodes are always last\r\n nodes = inputs.concat(nodes).concat(outputs);\r\n\r\n if (network.input === 0 || network.output === 0) {\r\n throw new Error('Given nodes have no clear input/output node!');\r\n }\r\n\r\n for (i = 0; i < nodes.length; i++) {\r\n let j;\r\n for (j = 0; j < nodes[i].connections.out.length; j++) {\r\n network.connections.push(nodes[i].connections.out[j]);\r\n }\r\n for (j = 0; j < nodes[i].connections.gated.length; j++) {\r\n network.gates.push(nodes[i].connections.gated[j]);\r\n }\r\n if (nodes[i].connections.self.weight !== 0) {\r\n network.selfconns.push(nodes[i].connections.self);\r\n }\r\n }\r\n\r\n network.nodes = nodes;\r\n\r\n return network;\r\n },\r\n\r\n /**\r\n * Creates a multilayer perceptron (MLP)\r\n */\r\n Perceptron: function () {\r\n // Convert arguments to Array\r\n var layers = Array.prototype.slice.call(arguments);\r\n if (layers.length < 3) {\r\n throw new Error('You have to specify at least 3 layers');\r\n }\r\n\r\n // Create a list of nodes/groups\r\n var nodes = [];\r\n nodes.push(new Group(layers[0]));\r\n\r\n for (var i = 1; i < layers.length; i++) {\r\n var layer = layers[i];\r\n layer = new Group(layer);\r\n nodes.push(layer);\r\n nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL);\r\n }\r\n\r\n // Construct the network\r\n return architect.Construct(nodes);\r\n },\r\n\r\n /**\r\n * Creates a randomly connected network\r\n */\r\n Random: function (input, hidden, output, options) {\r\n options = options || {};\r\n\r\n var connections = options.connections || hidden * 2;\r\n var backconnections = options.backconnections || 0;\r\n var selfconnections = options.selfconnections || 0;\r\n var gates = options.gates || 0;\r\n\r\n var network = new Network(input, output);\r\n\r\n var i;\r\n for (i = 0; i < hidden; i++) {\r\n network.mutate(methods.mutation.ADD_NODE);\r\n }\r\n\r\n for (i = 0; i < connections - hidden; i++) {\r\n network.mutate(methods.mutation.ADD_CONN);\r\n }\r\n\r\n for (i = 0; i < backconnections; i++) {\r\n network.mutate(methods.mutation.ADD_BACK_CONN);\r\n }\r\n\r\n for (i = 0; i < selfconnections; i++) {\r\n network.mutate(methods.mutation.ADD_SELF_CONN);\r\n }\r\n\r\n for (i = 0; i < gates; i++) {\r\n network.mutate(methods.mutation.ADD_GATE);\r\n }\r\n\r\n return network;\r\n },\r\n\r\n /**\r\n * Creates a long short-term memory network\r\n */\r\n LSTM: function () {\r\n var args = Array.prototype.slice.call(arguments);\r\n if (args.length < 3) {\r\n throw new Error('You have to specify at least 3 layers');\r\n }\r\n\r\n var last = args.pop();\r\n\r\n var outputLayer;\r\n if (typeof last === 'number') {\r\n outputLayer = new Group(last);\r\n last = {};\r\n } else {\r\n outputLayer = new Group(args.pop()); // last argument\r\n }\r\n\r\n outputLayer.set({\r\n type: 'output'\r\n });\r\n\r\n var options = {};\r\n options.memoryToMemory = last.memoryToMemory || false;\r\n options.outputToMemory = last.outputToMemory || false;\r\n options.outputToGates = last.outputToGates || false;\r\n options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput;\r\n options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep;\r\n\r\n var inputLayer = new Group(args.shift()); // first argument\r\n inputLayer.set({\r\n type: 'input'\r\n });\r\n\r\n var blocks = args; // all the arguments in the middle\r\n\r\n var nodes = [];\r\n nodes.push(inputLayer);\r\n\r\n var previous = inputLayer;\r\n for (var i = 0; i < blocks.length; i++) {\r\n var block = blocks[i];\r\n\r\n // Init required nodes (in activation order)\r\n var inputGate = new Group(block);\r\n var forgetGate = new Group(block);\r\n var memoryCell = new Group(block);\r\n var outputGate = new Group(block);\r\n var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block);\r\n\r\n inputGate.set({\r\n bias: 1\r\n });\r\n forgetGate.set({\r\n bias: 1\r\n });\r\n outputGate.set({\r\n bias: 1\r\n });\r\n\r\n // Connect the input with all the nodes\r\n var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL);\r\n previous.connect(inputGate, methods.connection.ALL_TO_ALL);\r\n previous.connect(outputGate, methods.connection.ALL_TO_ALL);\r\n previous.connect(forgetGate, methods.connection.ALL_TO_ALL);\r\n\r\n // Set up internal connections\r\n memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL);\r\n memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL);\r\n memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL);\r\n var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE);\r\n var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL);\r\n\r\n // Set up gates\r\n inputGate.gate(input, methods.gating.INPUT);\r\n forgetGate.gate(forget, methods.gating.SELF);\r\n outputGate.gate(output, methods.gating.OUTPUT);\r\n\r\n // Input to all memory cells\r\n if (options.inputToDeep && i > 0) {\r\n let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL);\r\n inputGate.gate(input, methods.gating.INPUT);\r\n }\r\n\r\n // Optional connections\r\n if (options.memoryToMemory) {\r\n let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE);\r\n inputGate.gate(input, methods.gating.INPUT);\r\n }\r\n\r\n if (options.outputToMemory) {\r\n let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL);\r\n inputGate.gate(input, methods.gating.INPUT);\r\n }\r\n\r\n if (options.outputToGates) {\r\n outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL);\r\n outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL);\r\n outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL);\r\n }\r\n\r\n // Add to array\r\n nodes.push(inputGate);\r\n nodes.push(forgetGate);\r\n nodes.push(memoryCell);\r\n nodes.push(outputGate);\r\n if (i !== blocks.length - 1) nodes.push(outputBlock);\r\n\r\n previous = outputBlock;\r\n }\r\n\r\n // input to output direct connection\r\n if (options.inputToOutput) {\r\n inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL);\r\n }\r\n\r\n nodes.push(outputLayer);\r\n return architect.Construct(nodes);\r\n },\r\n\r\n /**\r\n * Creates a gated recurrent unit network\r\n */\r\n GRU: function () {\r\n var args = Array.prototype.slice.call(arguments);\r\n if (args.length < 3) {\r\n throw new Error('not enough layers (minimum 3) !!');\r\n }\r\n\r\n var inputLayer = new Group(args.shift()); // first argument\r\n var outputLayer = new Group(args.pop()); // last argument\r\n var blocks = args; // all the arguments in the middle\r\n\r\n var nodes = [];\r\n nodes.push(inputLayer);\r\n\r\n var previous = inputLayer;\r\n for (var i = 0; i < blocks.length; i++) {\r\n var layer = new Layer.GRU(blocks[i]);\r\n previous.connect(layer);\r\n previous = layer;\r\n\r\n nodes.push(layer);\r\n }\r\n\r\n previous.connect(outputLayer);\r\n nodes.push(outputLayer);\r\n\r\n return architect.Construct(nodes);\r\n },\r\n\r\n /**\r\n * Creates a hopfield network of the given size\r\n */\r\n Hopfield: function (size) {\r\n var input = new Group(size);\r\n var output = new Group(size);\r\n\r\n input.connect(output, methods.connection.ALL_TO_ALL);\r\n\r\n input.set({\r\n type: 'input'\r\n });\r\n output.set({\r\n squash: methods.activation.STEP,\r\n type: 'output'\r\n });\r\n\r\n var network = new architect.Construct([input, output]);\r\n\r\n return network;\r\n },\r\n\r\n /**\r\n * Creates a NARX network (remember previous inputs/outputs)\r\n */\r\n NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) {\r\n if (!Array.isArray(hiddenLayers)) {\r\n hiddenLayers = [hiddenLayers];\r\n }\r\n\r\n var nodes = [];\r\n\r\n var input = new Layer.Dense(inputSize);\r\n var inputMemory = new Layer.Memory(inputSize, previousInput);\r\n var hidden = [];\r\n var output = new Layer.Dense(outputSize);\r\n var outputMemory = new Layer.Memory(outputSize, previousOutput);\r\n\r\n nodes.push(input);\r\n nodes.push(outputMemory);\r\n\r\n for (var i = 0; i < hiddenLayers.length; i++) {\r\n var hiddenLayer = new Layer.Dense(hiddenLayers[i]);\r\n hidden.push(hiddenLayer);\r\n nodes.push(hiddenLayer);\r\n if (typeof hidden[i - 1] !== 'undefined') {\r\n hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL);\r\n }\r\n }\r\n\r\n nodes.push(inputMemory);\r\n nodes.push(output);\r\n\r\n input.connect(hidden[0], methods.connection.ALL_TO_ALL);\r\n input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1);\r\n inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL);\r\n hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL);\r\n output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1);\r\n outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL);\r\n\r\n input.set({\r\n type: 'input'\r\n });\r\n output.set({\r\n type: 'output'\r\n });\r\n\r\n return architect.Construct(nodes);\r\n }\r\n};\r\n\r\n/* Export */\r\nmodule.exports = architect;\r\n", "var Neataptic = {\r\n methods: require('./methods/methods'),\r\n Connection: require('./architecture/connection'),\r\n architect: require('./architecture/architect'),\r\n Network: require('./architecture/network'),\r\n config: require('./config'),\r\n Group: require('./architecture/group'),\r\n Layer: require('./architecture/layer'),\r\n Node: require('./architecture/node'),\r\n Neat: require('./neat'),\r\n multi: require('./multithreading/multi')\r\n};\r\n\r\n// CommonJS & AMD\r\nif (typeof define !== 'undefined' && define.amd) {\r\n define([], function () { return Neataptic; });\r\n}\r\n\r\n// Node.js\r\nif (typeof module !== 'undefined' && module.exports) {\r\n module.exports = Neataptic;\r\n}\r\n\r\n// Browser\r\nif (typeof window === 'object') {\r\n (function () {\r\n var old = window['neataptic'];\r\n Neataptic.ninja = function () {\r\n window['neataptic'] = old;\r\n return Neataptic;\r\n };\r\n })();\r\n\r\n window['neataptic'] = Neataptic;\r\n}\r\n", "export default require(\"./node_modules/neataptic/src/neataptic.js\");"], - "mappings": ";;;;;;;AAAA;AAAA;AAMA,QAAI,aAAa;AAAA,MACf,UAAU,SAAU,GAAG,UAAU;AAC/B,YAAI,KAAK,IAAK,KAAI,KAAK,IAAI,CAAC;AAC5B,YAAI,CAAC;AAAU,iBAAO;AACtB,eAAO,KAAM,KAAI;AAAA;AAAA,MAEnB,MAAM,SAAU,GAAG,UAAU;AAC3B,YAAI;AAAU,iBAAO,IAAI,KAAK,IAAI,KAAK,KAAK,IAAI;AAChD,eAAO,KAAK,KAAK;AAAA;AAAA,MAEnB,UAAU,SAAU,GAAG,UAAU;AAC/B,eAAO,WAAW,IAAI;AAAA;AAAA,MAExB,MAAM,SAAU,GAAG,UAAU;AAC3B,eAAO,WAAW,IAAI,IAAI,IAAI,IAAI;AAAA;AAAA,MAEpC,MAAM,SAAU,GAAG,UAAU;AAC3B,YAAI;AAAU,iBAAO,IAAI,IAAI,IAAI;AACjC,eAAO,IAAI,IAAI,IAAI;AAAA;AAAA,MAErB,UAAU,SAAU,GAAG,UAAU;AAC/B,YAAI,IAAI,IAAI,KAAK,IAAI;AACrB,YAAI;AAAU,iBAAO,IAAI,KAAK,IAAI,GAAG;AACrC,eAAO,IAAI;AAAA;AAAA,MAEb,UAAU,SAAU,GAAG,UAAU;AAC/B,YAAI;AAAU,iBAAO,KAAK,IAAI;AAC9B,eAAO,KAAK,IAAI;AAAA;AAAA,MAElB,UAAU,SAAU,GAAG,UAAU;AAC/B,YAAI,IAAI,KAAK,IAAI,CAAC,KAAK,IAAI,GAAG;AAC9B,YAAI;AAAU,iBAAO,KAAK,IAAI;AAC9B,eAAO;AAAA;AAAA,MAET,eAAe,SAAU,GAAG,UAAU;AACpC,YAAI,IAAI,KAAK,KAAK,KAAK,IAAI,GAAG,KAAK;AACnC,YAAI;AAAU,iBAAO,IAAK,KAAI,KAAK;AACnC,eAAQ,KAAI,KAAK,IAAI;AAAA;AAAA,MAEvB,SAAS,SAAU,GAAG,UAAU;AAC9B,eAAO,WAAW,IAAI,IAAI,IAAI,IAAI;AAAA;AAAA,MAEpC,iBAAiB,SAAU,GAAG,UAAU;AACtC,YAAI,IAAI,IAAK,KAAI,KAAK,IAAI,CAAC,MAAM;AACjC,YAAI;AAAU,iBAAO,IAAI,IAAK,KAAI,KAAM,KAAI;AAC5C,eAAO;AAAA;AAAA,MAET,WAAW,SAAU,GAAG,UAAU;AAChC,YAAI;AAAU,iBAAO,IAAI,MAAM,IAAI,IAAI,IAAI;AAC3C,eAAO,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG;AAAA;AAAA,MAElC,UAAU,SAAU,GAAG,UAAU;AAC/B,YAAI;AAAU,iBAAO,IAAI,IAAI,KAAK;AAClC,eAAO,KAAK,IAAI;AAAA;AAAA,MAElB,SAAS,SAAU,GAAG,UAAU;AAC9B,YAAI;AAAU,iBAAO;AACrB,eAAO,IAAI;AAAA;AAAA,MAGb,MAAM,SAAU,GAAG,UAAU;AAC3B,YAAI,QAAQ;AACZ,YAAI,QAAQ;AACZ,YAAI,KAAK,IAAI,IAAI,IAAI,QAAQ,KAAK,IAAI,KAAK;AAC3C,YAAI,UAAU;AAAE,iBAAO,IAAI,IAAI,QAAS,MAAK,SAAS;AAAA;AACtD,eAAO,KAAK;AAAA;AAAA;AAKhB,WAAO,UAAU;AAAA;AAAA;;;AC5EjB;AAAA;AACA,QAAI,aAAa;AAOjB,QAAI,WAAW;AAAA,MACb,UAAU;AAAA,QACR,MAAM;AAAA;AAAA,MAER,UAAU;AAAA,QACR,MAAM;AAAA,QACN,YAAY;AAAA;AAAA,MAEd,UAAU;AAAA,QACR,MAAM;AAAA;AAAA,MAER,UAAU;AAAA,QACR,MAAM;AAAA;AAAA,MAER,YAAY;AAAA,QACV,MAAM;AAAA,QACN,KAAK;AAAA,QACL,KAAK;AAAA;AAAA,MAEP,UAAU;AAAA,QACR,MAAM;AAAA,QACN,KAAK;AAAA,QACL,KAAK;AAAA;AAAA,MAEP,gBAAgB;AAAA,QACd,MAAM;AAAA,QACN,cAAc;AAAA,QACd,SAAS;AAAA,UACP,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA,UACX,WAAW;AAAA;AAAA;AAAA,MAGf,eAAe;AAAA,QACb,MAAM;AAAA;AAAA,MAER,eAAe;AAAA,QACb,MAAM;AAAA;AAAA,MAER,UAAU;AAAA,QACR,MAAM;AAAA;AAAA,MAER,UAAU;AAAA,QACR,MAAM;AAAA;AAAA,MAER,eAAe;AAAA,QACb,MAAM;AAAA;AAAA,MAER,eAAe;AAAA,QACb,MAAM;AAAA;AAAA,MAER,YAAY;AAAA,QACV,MAAM;AAAA,QACN,cAAc;AAAA;AAAA;AAIlB,aAAS,MAAM;AAAA,MACb,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA;AAGX,aAAS,MAAM;AAAA,MACb,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA,MACT,SAAS;AAAA;AAIX,WAAO,UAAU;AAAA;AAAA;;;AC1GjB;AAAA;AAMA,QAAI,YAAY;AAAA,MACd,uBAAuB;AAAA,QACrB,MAAM;AAAA;AAAA,MAER,OAAO;AAAA,QACL,MAAM;AAAA,QACN,OAAO;AAAA;AAAA,MAET,YAAY;AAAA,QACV,MAAM;AAAA,QACN,MAAM;AAAA,QACN,aAAa;AAAA;AAAA;AAKjB,WAAO,UAAU;AAAA;AAAA;;;ACtBjB;AAAA;AAKA,QAAI,YAAY;AAAA,MACd,cAAc;AAAA,QACZ,MAAM;AAAA,QACN,QAAQ,CAAC;AAAA;AAAA,MAEX,WAAW;AAAA,QACT,MAAM;AAAA,QACN,QAAQ,CAAC,KAAK;AAAA;AAAA,MAEhB,SAAS;AAAA,QACP,MAAM;AAAA;AAAA,MAER,SAAS;AAAA,QACP,MAAM;AAAA;AAAA;AAKV,WAAO,UAAU;AAAA;AAAA;;;ACvBjB;AAAA;AAKA,QAAI,OAAO;AAAA,MAET,eAAe,SAAU,QAAQ,QAAQ;AACvC,YAAI,QAAQ;AACZ,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AAEtC,mBAAS,OAAO,KAAK,KAAK,IAAI,KAAK,IAAI,OAAO,IAAI,UAAW,KAAI,OAAO,MAAM,KAAK,IAAI,IAAI,KAAK,IAAI,OAAO,IAAI;AAAA;AAEjH,eAAO,QAAQ,OAAO;AAAA;AAAA,MAGxB,KAAK,SAAU,QAAQ,QAAQ;AAC7B,YAAI,QAAQ;AACZ,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,mBAAS,KAAK,IAAI,OAAO,KAAK,OAAO,IAAI;AAAA;AAG3C,eAAO,QAAQ,OAAO;AAAA;AAAA,MAGxB,QAAQ,SAAU,QAAQ,QAAQ;AAChC,YAAI,SAAS;AACb,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,oBAAU,KAAK,MAAM,OAAO,KAAK,OAAO,KAAK,MAAM,OAAO,KAAK;AAAA;AAGjE,eAAO;AAAA;AAAA,MAGT,KAAK,SAAU,QAAQ,QAAQ;AAC7B,YAAI,QAAQ;AACZ,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,mBAAS,KAAK,IAAI,OAAO,KAAK,OAAO;AAAA;AAGvC,eAAO,QAAQ,OAAO;AAAA;AAAA,MAGxB,MAAM,SAAU,QAAQ,QAAQ;AAC9B,YAAI,QAAQ;AACZ,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,mBAAS,KAAK,IAAK,QAAO,KAAK,OAAO,MAAM,KAAK,IAAI,OAAO,IAAI;AAAA;AAGlE,eAAO,QAAQ,OAAO;AAAA;AAAA,MAGxB,MAAM,SAAU,QAAQ,QAAQ;AAC9B,YAAI,QAAQ;AACZ,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,mBAAS,KAAK,IAAI,KAAK,IAAI,OAAO,IAAI,UAAU,KAAK,IAAI,KAAK,IAAI,OAAO,IAAI;AAAA;AAG/E,eAAO;AAAA;AAAA,MAGT,OAAO,SAAU,QAAQ,QAAQ;AAC/B,YAAI,QAAQ;AACZ,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,mBAAS,KAAK,IAAI,GAAG,IAAI,OAAO,KAAK,OAAO;AAAA;AAG9C,eAAO;AAAA;AAAA;AAKX,WAAO,UAAU;AAAA;AAAA;;;ACxEjB;AAAA;AAKA,QAAI,SAAS;AAAA,MACX,QAAQ;AAAA,QACN,MAAM;AAAA;AAAA,MAER,OAAO;AAAA,QACL,MAAM;AAAA;AAAA,MAER,MAAM;AAAA,QACJ,MAAM;AAAA;AAAA;AAKV,WAAO,UAAU;AAAA;AAAA;;;AClBjB;AAAA;AAKA,QAAI,aAAa;AAAA,MACf,YAAY;AAAA,QACV,MAAM;AAAA;AAAA,MAER,aAAa;AAAA,QACX,MAAM;AAAA;AAAA,MAER,YAAY;AAAA,QACV,MAAM;AAAA;AAAA;AAKV,WAAO,UAAU;AAAA;AAAA;;;AClBjB;AAAA;AAKA,QAAI,OAAO;AAAA,MACT,OAAO,WAAY;AACjB,YAAI,OAAO,SAAU,UAAU,WAAW;AAAE,iBAAO;AAAA;AACnD,eAAO;AAAA;AAAA,MAET,MAAM,SAAU,OAAO,UAAU;AAC/B,gBAAQ,SAAS;AACjB,mBAAW,YAAY;AAEvB,YAAI,OAAO,SAAU,UAAU,WAAW;AACxC,iBAAO,WAAW,KAAK,IAAI,OAAO,KAAK,MAAM,YAAY;AAAA;AAG3D,eAAO;AAAA;AAAA,MAET,KAAK,SAAU,OAAO;AACpB,gBAAQ,SAAS;AAEjB,YAAI,OAAO,SAAU,UAAU,WAAW;AACxC,iBAAO,WAAW,KAAK,IAAI,OAAO;AAAA;AAGpC,eAAO;AAAA;AAAA,MAET,KAAK,SAAU,OAAO,OAAO;AAC3B,gBAAQ,SAAS;AACjB,gBAAQ,SAAS;AAEjB,YAAI,OAAO,SAAU,UAAU,WAAW;AACxC,iBAAO,WAAW,KAAK,IAAI,IAAI,QAAQ,WAAW,CAAC;AAAA;AAGrD,eAAO;AAAA;AAAA;AAKX,WAAO,UAAU;AAAA;AAAA;;;AC1CjB;AAAA;AAIA,QAAI,UAAU;AAAA,MACZ,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,WAAW;AAAA,MACX,WAAW;AAAA,MACX,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,MAAM;AAAA;AAIR,WAAO,UAAU;AAAA;AAAA;;;AChBjB;AAAA;AACA,WAAO,UAAU;AAMjB,wBAAqB,MAAM,IAAI,QAAQ;AACrC,WAAK,OAAO;AACZ,WAAK,KAAK;AACV,WAAK,OAAO;AAEZ,WAAK,SAAU,OAAO,WAAW,cAAe,KAAK,WAAW,MAAM,MAAM;AAE5E,WAAK,QAAQ;AACb,WAAK,cAAc;AAGnB,WAAK,sBAAsB;AAG3B,WAAK,mBAAmB;AAExB,WAAK,SAAS;AAAA,QACZ,OAAO;AAAA,QACP,QAAQ;AAAA;AAAA;AAIZ,eAAW,YAAY;AAAA,MAIrB,QAAQ,WAAY;AAClB,YAAI,OAAO;AAAA,UACT,QAAQ,KAAK;AAAA;AAGf,eAAO;AAAA;AAAA;AAQX,eAAW,eAAe,SAAU,GAAG,GAAG;AACxC,aAAO,IAAI,IAAK,KAAI,KAAM,KAAI,IAAI,KAAK;AAAA;AAAA;AAAA;;;AC/CzC;AAAA;AAAA;AAAA;AAAA,IAAO;AAAP;AAAA;AAAA,IAAO,wBAAQ,IAAI,MAAM,IAAI;AAAA,MAC3B,MAAM;AACJ,cAAM,IAAI,MAAM;AAAA;AAAA;AAAA;AAAA;;;ACFpB;AAAA;AAAA;AAAA;AAAA,IAAO;AAAP;AAAA;AAAA,IAAO,eAAQ,IAAI,MAAM,IAAI;AAAA,MAC3B,MAAM;AACJ,cAAM,IAAI,MAAM;AAAA;AAAA;AAAA;AAAA;;;ACFpB;AAAA;AACA,WAAO,UAAU;AAGjB,QAAI,KAAK;AACT,QAAI,OAAO;AAMX,wBAAqB,SAAS,MAAM;AAClC,WAAK,SAAS,GAAG,KAAK,KAAK,KAAK,WAAW;AAE3C,WAAK,OAAO,KAAK,EAAE,KAAK,SAAS,MAAM,KAAK;AAAA;AAG9C,eAAW,YAAY;AAAA,MACrB,UAAU,SAAU,SAAS;AAC3B,eAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,cAAI,aAAa,QAAQ;AAEzB,cAAI,OAAO;AAAA,YACT,aAAa,WAAW;AAAA,YACxB,QAAQ,WAAW;AAAA,YACnB,OAAO,WAAW;AAAA;AAGpB,cAAI,QAAQ,KAAK;AACjB,eAAK,OAAO,GAAG,WAAW,kBAAmB,GAAG;AAC9C,kBAAM,eAAe,WAAW;AAChC,oBAAQ;AAAA;AAGV,eAAK,OAAO,KAAK;AAAA;AAAA;AAAA,MAIrB,WAAW,WAAY;AACrB,aAAK,OAAO;AAAA;AAAA;AAAA;AAAA;;;ACvChB;AAAA;AACA,WAAO,UAAU;AAGjB,QAAI,QAAQ;AAMZ,wBAAqB,SAAS,MAAM;AAClC,UAAI,OAAO,IAAI,KAAK,CAAC,KAAK,kBAAkB;AAC5C,WAAK,MAAM,OAAO,IAAI,gBAAgB;AACtC,WAAK,SAAS,IAAI,OAAO,KAAK;AAE9B,UAAI,OAAO,EAAE,KAAK,IAAI,aAAa,SAAS;AAC5C,WAAK,OAAO,YAAY,MAAM,CAAC,KAAK;AAAA;AAGtC,eAAW,YAAY;AAAA,MACrB,UAAU,SAAU,SAAS;AAC3B,eAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,cAAI,aAAa,QAAQ;AAEzB,cAAI,OAAO;AAAA,YACT,aAAa,IAAI,aAAa,WAAW,IAAI;AAAA,YAC7C,QAAQ,IAAI,aAAa,WAAW,IAAI;AAAA,YACxC,OAAO,IAAI,aAAa,WAAW,IAAI;AAAA;AAGzC,eAAK,OAAO,YAAY,SAAU,GAAG;AACnC,gBAAI,QAAQ,IAAI,aAAa,EAAE,KAAK,QAAQ;AAC5C,oBAAQ;AAAA;AAGV,eAAK,OAAO,YAAY,MAAM,CAAC,KAAK,aAAa,KAAK,QAAQ,KAAK;AAAA;AAAA;AAAA,MAIvE,WAAW,WAAY;AACrB,aAAK,OAAO;AACZ,eAAO,IAAI,gBAAgB,KAAK;AAAA;AAAA,MAGlC,mBAAmB,SAAU,MAAM;AACjC,YAAI,SAAS;AAAA,iBACA,MAAM,YAAY;AAAA,mBAChB,KAAK;AAAA;AAAA,8BAEM,MAAM,mBAAmB;AAAA,6BAC1B,MAAM,kBAAkB;AAAA,qCAChB,MAAM,0BAA0B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBjE,eAAO;AAAA;AAAA;AAAA;AAAA;;;ACrEX;AAAA;AAIA,QAAI,UAAU;AAAA,MACZ,MAAM;AAAA,QACJ,YAAY;AAAA;AAAA,MAEd,SAAS;AAAA,QACP,YAAY;AAAA;AAAA;AAKhB,WAAO,UAAU;AAAA;AAAA;;;ACdjB;AAAA;AAIA,QAAI,QAAQ;AAAA,MAEV,SAAS;AAAA,MAGT,kBAAkB,SAAU,SAAS;AACnC,YAAI,aAAa,CAAC,QAAQ,GAAG,MAAM,QAAQ,QAAQ,GAAG,OAAO;AAE7D,iBAAS,KAAI,GAAG,KAAI,QAAQ,QAAQ,MAAK;AACvC,cAAI;AACJ,eAAK,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK;AAClC,uBAAW,KAAK,QAAQ,IAAG,MAAM;AAAA;AAEnC,eAAK,IAAI,GAAG,IAAI,WAAW,IAAI,KAAK;AAClC,uBAAW,KAAK,QAAQ,IAAG,OAAO;AAAA;AAAA;AAItC,eAAO;AAAA;AAAA,MAIT,2BAA2B,SAAU,OAAO,GAAG,GAAG,MAAM,GAAG;AACzD,iBAAS,KAAI,GAAG,KAAI,KAAK,IAAI;AAAK,YAAE,MAAK,MAAM;AAC/C,aAAK,KAAI,GAAG,KAAI,KAAK,QAAQ,MAAK;AAChC,cAAI,QAAQ,KAAK;AACjB,cAAI,OAAO,KAAK;AAChB,cAAI,SAAS,KAAK;AAClB,cAAI,aAAa,KAAK;AACtB,cAAI,YAAY,KAAK;AAErB,YAAE,SAAU,eAAc,KAAK,IAAI,EAAE,cAAc,aAAa,EAAE,SAAS;AAE3E,iBAAO,KAAK,QAAO,IAAI;AACrB,cAAE,UAAU,EAAE,KAAK,SAAQ,KAAK,QAAQ,MAAK,UAAS,KAAK,IAAI,EAAE,KAAK,KAAI;AAAA;AAE5E,YAAE,SAAS,EAAE,QAAQ,EAAE;AAAA;AAGzB,YAAI,SAAS;AACb,aAAK,KAAI,EAAE,SAAS,KAAK,IAAI,KAAI,EAAE,QAAQ;AAAK,iBAAO,KAAK,EAAE;AAC9D,eAAO;AAAA;AAAA,MAIT,oBAAoB,SAAU,eAAe;AAC3C,YAAI,MAAM;AAEV,YAAI,aAAa,cAAc,KAAK,cAAc;AAClD,iBAAS,KAAI,GAAG,KAAK,eAAc,SAAS,KAAK,YAAY,MAAK;AAChE,cAAI,QAAQ;AACZ,mBAAS,IAAI,IAAI,KAAI,YAAY,IAAI,IAAI,KAAI,aAAa,cAAc,IAAI,KAAK;AAC/E,kBAAM,KAAK,cAAc;AAAA;AAE3B,cAAI,SAAS;AACb,eAAK,IAAI,IAAI,KAAI,aAAa,cAAc,IAAI,IAAI,IAAI,KAAI,aAAa,YAAY,KAAK;AACxF,mBAAO,KAAK,cAAc;AAAA;AAE5B,cAAI,KAAK;AACT,cAAI,KAAK;AAAA;AAGX,eAAO;AAAA;AAAA,MAIT,aAAa;AAAA,QACX,SAAU,GAAG;AAAE,iBAAO,IAAK,KAAI,KAAK,IAAI,CAAC;AAAA;AAAA,QACzC,SAAU,GAAG;AAAE,iBAAO,KAAK,KAAK;AAAA;AAAA,QAChC,SAAU,GAAG;AAAE,iBAAO;AAAA;AAAA,QACtB,SAAU,GAAG;AAAE,iBAAO,IAAI,IAAI,IAAI;AAAA;AAAA,QAClC,SAAU,GAAG;AAAE,iBAAO,IAAI,IAAI,IAAI;AAAA;AAAA,QAClC,SAAU,GAAG;AAAE,iBAAO,IAAK,KAAI,KAAK,IAAI;AAAA;AAAA,QACxC,SAAU,GAAG;AAAE,iBAAO,KAAK,IAAI;AAAA;AAAA,QAC/B,SAAU,GAAG;AAAE,iBAAO,KAAK,IAAI,CAAC,KAAK,IAAI,GAAG;AAAA;AAAA,QAC5C,SAAU,GAAG;AAAE,iBAAQ,MAAK,KAAK,KAAK,IAAI,GAAG,KAAK,KAAK,KAAK,IAAI;AAAA;AAAA,QAChE,SAAU,GAAG;AAAE,iBAAO,IAAI,IAAI,IAAI;AAAA;AAAA,QAClC,SAAU,GAAG;AAAE,iBAAO,IAAK,KAAI,KAAK,IAAI,CAAC,MAAM;AAAA;AAAA,QAC/C,SAAU,GAAG;AAAE,iBAAO,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG;AAAA;AAAA,QAC/C,SAAU,GAAG;AAAE,iBAAO,KAAK,IAAI;AAAA;AAAA,QAC/B,SAAU,GAAG;AAAE,iBAAO,IAAI;AAAA;AAAA,QAC1B,SAAU,GAAG;AACX,cAAI,IAAI;AACR,iBAAQ,KAAI,IAAI,IAAI,IAAI,KAAK,IAAI,KAAK,KAAK;AAAA;AAAA;AAAA;AAKjD,UAAM,oBAAoB,SAAU,KAAK,MAAM,GAAG,GAAG,MAAM,GAAG;AAE5D,UAAI,QAAQ;AACZ,eAAS,KAAI,GAAG,KAAI,IAAI,QAAQ,MAAK,GAAG;AACtC,YAAI,SAAS,MAAM,0BAA0B,IAAI,KAAI,GAAG,GAAG,MAAM;AACjE,iBAAS,KAAK,IAAI,KAAI,IAAI;AAAA;AAG5B,aAAO,QAAS,KAAI,SAAS;AAAA;AAI/B,SAAS,KAAK,OAAO;AACnB,aAAO,QAAQ,KAAK,MAAM;AAAA;AADnB;AAAA;AAAA;;;ACxGT;AAAA;AAKA,QAAI,SAAS;AAAA,MACX,UAAU;AAAA;AAIZ,WAAO,UAAU;AAAA;AAAA;;;ACVjB;AAAA;AACA,WAAO,UAAU;AAGjB,QAAI,UAAU;AACd,QAAI,UAAU;AACd,QAAI,SAAS;AAGb,QAAI,YAAY,QAAQ;AAMxB,kBAAe,OAAO,QAAQ,SAAS,SAAS;AAC9C,WAAK,QAAQ;AACb,WAAK,SAAS;AACd,WAAK,UAAU;AAGf,gBAAU,WAAW;AACrB,WAAK,QAAQ,QAAQ,SAAS;AAC9B,WAAK,QAAQ,QAAQ,SAAS;AAC9B,WAAK,UAAU,QAAQ,WAAW;AAClC,WAAK,UAAU,QAAQ,WAAW;AAClC,WAAK,aAAa,QAAQ,cAAc;AACxC,WAAK,eAAe,QAAQ,gBAAgB;AAC5C,WAAK,iBAAiB,QAAQ,kBAAkB;AAEhD,WAAK,oBAAoB,QAAQ,qBAAqB;AAEtD,WAAK,YAAY,QAAQ,aAAa,QAAQ,UAAU;AACxD,WAAK,YAAY,QAAQ,aAAa;AAAA,QACpC,QAAQ,UAAU;AAAA,QAClB,QAAQ,UAAU;AAAA,QAClB,QAAQ,UAAU;AAAA,QAClB,QAAQ,UAAU;AAAA;AAEpB,WAAK,WAAW,QAAQ,YAAY,QAAQ,SAAS;AAErD,WAAK,WAAW,QAAQ,WAAW;AAEnC,WAAK,WAAW,QAAQ,YAAY;AACpC,WAAK,WAAW,QAAQ,YAAY;AACpC,WAAK,WAAW,QAAQ,YAAY;AAGpC,WAAK,uBAAuB,OAAO,QAAQ,sBAAsB,aAAa,QAAQ,kBAAkB,KAAK,QAAQ,KAAK;AAG1H,WAAK,aAAa;AAGlB,WAAK,WAAW,KAAK;AAAA;AAGvB,SAAK,YAAY;AAAA,MAIf,YAAY,SAAU,SAAS;AAC7B,aAAK,aAAa;AAElB,iBAAS,IAAI,GAAG,IAAI,KAAK,SAAS,KAAK;AACrC,cAAI;AACJ,cAAI,KAAK,UAAU;AACjB,mBAAO,QAAQ,SAAS,QAAQ;AAAA,iBAC3B;AACL,mBAAO,IAAI,QAAQ,KAAK,OAAO,KAAK;AAAA;AAEtC,eAAK,QAAQ;AACb,eAAK,WAAW,KAAK;AAAA;AAAA;AAAA,MAOzB,QAAQ,iBAAkB;AAExB,YAAI,OAAO,KAAK,WAAW,KAAK,WAAW,SAAS,GAAG,UAAU,aAAa;AAC5E,gBAAM,KAAK;AAAA;AAEb,aAAK;AAEL,YAAI,UAAU,QAAQ,SAAS,KAAK,WAAW,GAAG;AAClD,gBAAQ,QAAQ,KAAK,WAAW,GAAG;AAEnC,YAAI,gBAAgB;AAGpB,YAAI,WAAW;AACf,iBAAS,IAAI,GAAG,IAAI,KAAK,SAAS,KAAK;AACrC,mBAAS,KAAK,KAAK,WAAW;AAAA;AAIhC,aAAK,IAAI,GAAG,IAAI,KAAK,YAAY,KAAK;AACpC,wBAAc,KAAK,QAAQ,SAAS,KAAK,SAAS;AAAA;AAIpD,aAAK,IAAI,GAAG,IAAI,KAAK,UAAU,KAAK,UAAU,KAAK,YAAY,KAAK;AAClE,wBAAc,KAAK,KAAK;AAAA;AAI1B,aAAK,aAAa;AAClB,aAAK;AAEL,aAAK,WAAW,KAAK,GAAG;AAGxB,aAAK,IAAI,GAAG,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC3C,eAAK,WAAW,GAAG,QAAQ;AAAA;AAG7B,aAAK;AAEL,eAAO;AAAA;AAAA,MAMT,cAAc,WAAY;AACxB,YAAI,UAAU,KAAK;AACnB,YAAI,UAAU,KAAK;AAEnB,eAAO,QAAQ,UAAU,SAAS,SAAS,KAAK;AAAA;AAAA,MAMlD,sBAAsB,SAAU,QAAQ;AACtC,YAAI,iBAAiB,KAAK,SAAS,KAAK,MAAM,KAAK,WAAW,KAAK,SAAS;AAE5E,YAAI,mBAAmB,QAAQ,SAAS,YAAY,OAAO,MAAM,UAAU,KAAK,UAAU;AACxF,cAAI,OAAO;AAAU,oBAAQ,KAAK;AAClC;AAAA;AAGF,YAAI,mBAAmB,QAAQ,SAAS,YAAY,OAAO,YAAY,UAAU,KAAK,UAAU;AAC9F,cAAI,OAAO;AAAU,oBAAQ,KAAK;AAClC;AAAA;AAGF,YAAI,mBAAmB,QAAQ,SAAS,YAAY,OAAO,MAAM,UAAU,KAAK,UAAU;AACxF,cAAI,OAAO;AAAU,oBAAQ,KAAK;AAClC;AAAA;AAGF,eAAO;AAAA;AAAA,MAMT,QAAQ,WAAY;AAElB,iBAAS,IAAI,GAAG,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC/C,cAAI,KAAK,YAAY,KAAK,cAAc;AACtC,qBAAS,IAAI,GAAG,IAAI,KAAK,gBAAgB,KAAK;AAC5C,kBAAI,iBAAiB,KAAK,qBAAqB,KAAK,WAAW;AAC/D,mBAAK,WAAW,GAAG,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,MASlC,UAAU,iBAAkB;AAC1B,YAAI;AACJ,YAAI,KAAK,mBAAmB;AAC1B,cAAI,KAAK,OAAO;AACd,iBAAK,IAAI,GAAG,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC3C,mBAAK,WAAW,GAAG;AAAA;AAAA;AAGvB,gBAAM,KAAK,QAAQ,KAAK;AAAA,eACnB;AACL,eAAK,IAAI,GAAG,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC3C,gBAAI,SAAS,KAAK,WAAW;AAC7B,gBAAI,KAAK;AAAO,qBAAO;AACvB,mBAAO,QAAQ,MAAM,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA,MAQxC,MAAM,WAAY;AAChB,aAAK,WAAW,KAAK,SAAU,GAAG,GAAG;AACnC,iBAAO,EAAE,QAAQ,EAAE;AAAA;AAAA;AAAA,MAOvB,YAAY,WAAY;AAEtB,YAAI,OAAO,KAAK,WAAW,KAAK,WAAW,SAAS,GAAG,UAAU,aAAa;AAC5E,eAAK;AAAA;AAEP,YAAI,KAAK,WAAW,GAAG,QAAQ,KAAK,WAAW,GAAG,OAAO;AACvD,eAAK;AAAA;AAGP,eAAO,KAAK,WAAW;AAAA;AAAA,MAMzB,YAAY,WAAY;AACtB,YAAI,OAAO,KAAK,WAAW,KAAK,WAAW,SAAS,GAAG,UAAU,aAAa;AAC5E,eAAK;AAAA;AAGP,YAAI,QAAQ;AACZ,iBAAS,IAAI,GAAG,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC/C,mBAAS,KAAK,WAAW,GAAG;AAAA;AAG9B,eAAO,QAAQ,KAAK,WAAW;AAAA;AAAA,MAOjC,WAAW,WAAY;AACrB,YAAI;AACJ,gBAAQ,KAAK;AAAA,eACN,UAAU;AACb,gBAAI,KAAK,WAAW,GAAG,QAAQ,KAAK,WAAW,GAAG;AAAO,mBAAK;AAE9D,gBAAI,QAAQ,KAAK,MAAM,KAAK,IAAI,KAAK,UAAU,KAAK,UAAU,SAAS,KAAK,WAAW;AACvF,mBAAO,KAAK,WAAW;AAAA,eACpB,UAAU;AAKb,gBAAI,eAAe;AACnB,gBAAI,iBAAiB;AACrB,iBAAK,IAAI,GAAG,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC3C,kBAAI,QAAQ,KAAK,WAAW,GAAG;AAC/B,+BAAiB,QAAQ,iBAAiB,QAAQ;AAClD,8BAAgB;AAAA;AAGlB,6BAAiB,KAAK,IAAI;AAC1B,4BAAgB,iBAAiB,KAAK,WAAW;AAEjD,gBAAI,SAAS,KAAK,WAAW;AAC7B,gBAAI,QAAQ;AAEZ,iBAAK,IAAI,GAAG,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC3C,kBAAI,SAAS,KAAK,WAAW;AAC7B,uBAAS,OAAO,QAAQ;AACxB,kBAAI,SAAS;AAAO,uBAAO;AAAA;AAI7B,mBAAO,KAAK,WAAW,KAAK,MAAM,KAAK,WAAW,KAAK,WAAW;AAAA,eAC/D,UAAU;AACb,gBAAI,KAAK,UAAU,OAAO,KAAK,SAAS;AACtC,oBAAM,IAAI,MAAM;AAAA;AAIlB,gBAAI,cAAc;AAClB,iBAAK,IAAI,GAAG,IAAI,KAAK,UAAU,MAAM,KAAK;AACxC,kBAAI,UAAS,KAAK,WAAW,KAAK,MAAM,KAAK,WAAW,KAAK,WAAW;AACxE,0BAAY,KAAK;AAAA;AAInB,wBAAY,KAAK,SAAU,GAAG,GAAG;AAC/B,qBAAO,EAAE,QAAQ,EAAE;AAAA;AAIrB,iBAAK,IAAI,GAAG,IAAI,KAAK,UAAU,MAAM,KAAK;AACxC,kBAAI,KAAK,WAAW,KAAK,UAAU,eAAe,MAAM,KAAK,UAAU,OAAO,GAAG;AAC/E,uBAAO,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAS7B,QAAQ,WAAY;AAClB,YAAI,OAAO;AACX,iBAAS,IAAI,GAAG,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC/C,cAAI,SAAS,KAAK,WAAW;AAC7B,eAAK,KAAK,OAAO;AAAA;AAGnB,eAAO;AAAA;AAAA,MAMT,QAAQ,SAAU,MAAM;AACtB,YAAI,aAAa;AACjB,iBAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,cAAI,SAAS,KAAK;AAClB,qBAAW,KAAK,QAAQ,SAAS;AAAA;AAEnC,aAAK,aAAa;AAClB,aAAK,UAAU,WAAW;AAAA;AAAA;AAAA;AAAA;;;ACjU9B;AAAA;AACA,WAAO,UAAU;AAGjB,QAAI,UAAU;AACd,QAAI,aAAa;AACjB,QAAI,SAAS;AAMb,kBAAe,MAAM;AACnB,WAAK,OAAQ,SAAS,UAAW,IAAI,KAAK,WAAW,MAAM;AAC3D,WAAK,SAAS,QAAQ,WAAW;AACjC,WAAK,OAAO,QAAQ;AAEpB,WAAK,aAAa;AAClB,WAAK,QAAQ;AACb,WAAK,MAAM;AAGX,WAAK,OAAO;AAGZ,WAAK,oBAAoB;AAGzB,WAAK,iBAAiB;AAEtB,WAAK,cAAc;AAAA,QACjB,IAAI;AAAA,QACJ,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM,IAAI,WAAW,MAAM,MAAM;AAAA;AAInC,WAAK,QAAQ;AAAA,QACX,gBAAgB;AAAA,QAChB,WAAW;AAAA,QACX,OAAO;AAAA;AAAA;AAIX,SAAK,YAAY;AAAA,MAIf,UAAU,SAAU,OAAO;AAEzB,YAAI,OAAO,UAAU,aAAa;AAChC,eAAK,aAAa;AAClB,iBAAO,KAAK;AAAA;AAGd,aAAK,MAAM,KAAK;AAGhB,aAAK,QAAQ,KAAK,YAAY,KAAK,OAAO,KAAK,YAAY,KAAK,SAAS,KAAK,QAAQ,KAAK;AAG3F,YAAI;AACJ,aAAK,IAAI,GAAG,IAAI,KAAK,YAAY,GAAG,QAAQ,KAAK;AAC/C,cAAI,aAAa,KAAK,YAAY,GAAG;AACrC,eAAK,SAAS,WAAW,KAAK,aAAa,WAAW,SAAS,WAAW;AAAA;AAI5E,aAAK,aAAa,KAAK,OAAO,KAAK,SAAS,KAAK;AACjD,aAAK,aAAa,KAAK,OAAO,KAAK,OAAO;AAG1C,YAAI,QAAQ;AACZ,YAAI,aAAa;AAEjB,aAAK,IAAI,GAAG,IAAI,KAAK,YAAY,MAAM,QAAQ,KAAK;AAClD,cAAI,OAAO,KAAK,YAAY,MAAM;AAClC,cAAI,OAAO,KAAK;AAEhB,cAAI,QAAQ,MAAM,QAAQ;AAC1B,cAAI,QAAQ,IAAI;AACd,uBAAW,UAAU,KAAK,SAAS,KAAK,KAAK;AAAA,iBACxC;AACL,kBAAM,KAAK;AACX,uBAAW,KAAK,KAAK,SAAS,KAAK,KAAK,aACrC,MAAK,YAAY,KAAK,UAAU,OAAO,KAAK,MAAM;AAAA;AAIvD,eAAK,OAAO,KAAK;AAAA;AAGnB,aAAK,IAAI,GAAG,IAAI,KAAK,YAAY,GAAG,QAAQ,KAAK;AAC/C,cAAI,cAAa,KAAK,YAAY,GAAG;AAGrC,sBAAW,cAAc,KAAK,YAAY,KAAK,OAAO,KAAK,YAAY,KAAK,SAC1E,YAAW,cAAc,YAAW,KAAK,aAAa,YAAW;AAGnE,mBAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,gBAAI,OAAO,MAAM;AACjB,gBAAI,YAAY,WAAW;AAE3B,gBAAI,QAAQ,YAAW,OAAO,MAAM,QAAQ;AAE5C,gBAAI,QAAQ,IAAI;AACd,0BAAW,OAAO,OAAO,SAAS,KAAK,YAAY,KAAK,OAAO,KAAK,YAAY,KAAK,SACnF,YAAW,OAAO,OAAO,SAAS,KAAK,aAAa,YAAW,cAAc;AAAA,mBAC1E;AAEL,0BAAW,OAAO,MAAM,KAAK;AAC7B,0BAAW,OAAO,OAAO,KAAK,KAAK,aAAa,YAAW,cAAc;AAAA;AAAA;AAAA;AAK/E,eAAO,KAAK;AAAA;AAAA,MAMd,iBAAiB,SAAU,OAAO;AAEhC,YAAI,OAAO,UAAU,aAAa;AAChC,eAAK,aAAa;AAClB,iBAAO,KAAK;AAAA;AAId,aAAK,QAAQ,KAAK,YAAY,KAAK,OAAO,KAAK,YAAY,KAAK,SAAS,KAAK,QAAQ,KAAK;AAG3F,YAAI;AACJ,aAAK,IAAI,GAAG,IAAI,KAAK,YAAY,GAAG,QAAQ,KAAK;AAC/C,cAAI,aAAa,KAAK,YAAY,GAAG;AACrC,eAAK,SAAS,WAAW,KAAK,aAAa,WAAW,SAAS,WAAW;AAAA;AAI5E,aAAK,aAAa,KAAK,OAAO,KAAK;AAEnC,aAAK,IAAI,GAAG,IAAI,KAAK,YAAY,MAAM,QAAQ,KAAK;AAClD,eAAK,YAAY,MAAM,GAAG,OAAO,KAAK;AAAA;AAGxC,eAAO,KAAK;AAAA;AAAA,MAMd,WAAW,SAAU,MAAM,UAAU,QAAQ,QAAQ;AACnD,mBAAW,YAAY;AACvB,eAAO,QAAQ;AAGf,YAAI,QAAQ;AAGZ,YAAI,KAAK,SAAS,UAAU;AAC1B,eAAK,MAAM,iBAAiB,KAAK,MAAM,YAAY,SAAS,KAAK;AAAA,eAC5D;AAEL,cAAI;AACJ,eAAK,IAAI,GAAG,IAAI,KAAK,YAAY,IAAI,QAAQ,KAAK;AAChD,gBAAI,aAAa,KAAK,YAAY,IAAI;AACtC,gBAAI,OAAO,WAAW;AAEtB,qBAAS,KAAK,MAAM,iBAAiB,WAAW,SAAS,WAAW;AAAA;AAItE,eAAK,MAAM,YAAY,KAAK,aAAa;AAGzC,kBAAQ;AAER,eAAK,IAAI,GAAG,IAAI,KAAK,YAAY,MAAM,QAAQ,KAAK;AAClD,gBAAI,OAAO,KAAK,YAAY,MAAM;AAClC,gBAAI,OAAO,KAAK;AAChB,gBAAI,YAAY,KAAK,YAAY,KAAK,UAAU,OAAO,KAAK,MAAM;AAElE,yBAAa,KAAK,SAAS,KAAK,KAAK;AACrC,qBAAS,KAAK,MAAM,iBAAiB;AAAA;AAIvC,eAAK,MAAM,QAAQ,KAAK,aAAa;AAGrC,eAAK,MAAM,iBAAiB,KAAK,MAAM,YAAY,KAAK,MAAM;AAAA;AAGhE,YAAI,KAAK,SAAS;AAAY;AAG9B,aAAK,IAAI,GAAG,IAAI,KAAK,YAAY,GAAG,QAAQ,KAAK;AAC/C,cAAI,aAAa,KAAK,YAAY,GAAG;AAErC,cAAI,WAAW,KAAK,MAAM,YAAY,WAAW;AAEjD,mBAAS,IAAI,GAAG,IAAI,WAAW,OAAO,MAAM,QAAQ,KAAK;AACvD,gBAAI,OAAO,WAAW,OAAO,MAAM;AACnC,gBAAI,QAAQ,WAAW,OAAO,OAAO;AACrC,wBAAY,KAAK,MAAM,iBAAiB;AAAA;AAI1C,cAAI,cAAc,OAAO,WAAW,KAAK;AACzC,qBAAW,oBAAoB;AAC/B,cAAI,QAAQ;AACV,uBAAW,oBAAoB,WAAW,WAAW;AACrD,uBAAW,UAAU,WAAW;AAChC,uBAAW,sBAAsB,WAAW;AAC5C,uBAAW,mBAAmB;AAAA;AAAA;AAKlC,YAAI,YAAY,OAAO,KAAK,MAAM;AAClC,aAAK,kBAAkB;AACvB,YAAI,QAAQ;AACV,eAAK,kBAAkB,WAAW,KAAK;AACvC,eAAK,QAAQ,KAAK;AAClB,eAAK,oBAAoB,KAAK;AAC9B,eAAK,iBAAiB;AAAA;AAAA;AAAA,MAO1B,SAAS,SAAU,QAAQ,QAAQ;AACjC,YAAI,cAAc;AAClB,YAAI,OAAO,OAAO,SAAS,aAAa;AACtC,cAAI,WAAW,MAAM;AAEnB,gBAAI,KAAK,YAAY,KAAK,WAAW,GAAG;AACtC,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAAA,mBAC7B;AACL,mBAAK,YAAY,KAAK,SAAS,UAAU;AAAA;AAE3C,wBAAY,KAAK,KAAK,YAAY;AAAA,qBACzB,KAAK,eAAe,SAAS;AACtC,kBAAM,IAAI,MAAM;AAAA,iBACX;AACL,gBAAI,aAAa,IAAI,WAAW,MAAM,QAAQ;AAC9C,mBAAO,YAAY,GAAG,KAAK;AAC3B,iBAAK,YAAY,IAAI,KAAK;AAE1B,wBAAY,KAAK;AAAA;AAAA,eAEd;AACL,mBAAS,IAAI,GAAG,IAAI,OAAO,MAAM,QAAQ,KAAK;AAC5C,gBAAI,aAAa,IAAI,WAAW,MAAM,OAAO,MAAM,IAAI;AACvD,mBAAO,MAAM,GAAG,YAAY,GAAG,KAAK;AACpC,iBAAK,YAAY,IAAI,KAAK;AAC1B,mBAAO,YAAY,GAAG,KAAK;AAE3B,wBAAY,KAAK;AAAA;AAAA;AAGrB,eAAO;AAAA;AAAA,MAMT,YAAY,SAAU,MAAM,UAAU;AACpC,YAAI,SAAS,MAAM;AACjB,eAAK,YAAY,KAAK,SAAS;AAC/B;AAAA;AAGF,iBAAS,IAAI,GAAG,IAAI,KAAK,YAAY,IAAI,QAAQ,KAAK;AACpD,cAAI,OAAO,KAAK,YAAY,IAAI;AAChC,cAAI,KAAK,OAAO,MAAM;AACpB,iBAAK,YAAY,IAAI,OAAO,GAAG;AAC/B,gBAAI,IAAI,KAAK,GAAG,YAAY,GAAG,QAAQ;AACvC,iBAAK,GAAG,YAAY,GAAG,OAAO,GAAG;AACjC,gBAAI,KAAK,UAAU;AAAM,mBAAK,MAAM,OAAO;AAC3C;AAAA;AAAA;AAIJ,YAAI,UAAU;AACZ,eAAK,WAAW;AAAA;AAAA;AAAA,MAOpB,MAAM,SAAU,aAAa;AAC3B,YAAI,CAAC,MAAM,QAAQ,cAAc;AAC/B,wBAAc,CAAC;AAAA;AAGjB,iBAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,cAAI,aAAa,YAAY;AAE7B,eAAK,YAAY,MAAM,KAAK;AAC5B,qBAAW,QAAQ;AAAA;AAAA;AAAA,MAOvB,QAAQ,SAAU,aAAa;AAC7B,YAAI,CAAC,MAAM,QAAQ,cAAc;AAC/B,wBAAc,CAAC;AAAA;AAGjB,iBAAS,IAAI,YAAY,SAAS,GAAG,KAAK,GAAG,KAAK;AAChD,cAAI,aAAa,YAAY;AAE7B,cAAI,QAAQ,KAAK,YAAY,MAAM,QAAQ;AAC3C,eAAK,YAAY,MAAM,OAAO,OAAO;AACrC,qBAAW,QAAQ;AACnB,qBAAW,OAAO;AAAA;AAAA;AAAA,MAOtB,OAAO,WAAY;AACjB,iBAAS,IAAI,GAAG,IAAI,KAAK,YAAY,GAAG,QAAQ,KAAK;AACnD,cAAI,aAAa,KAAK,YAAY,GAAG;AAErC,qBAAW,cAAc;AACzB,qBAAW,SAAS;AAAA,YAClB,OAAO;AAAA,YACP,QAAQ;AAAA;AAAA;AAIZ,aAAK,IAAI,GAAG,IAAI,KAAK,YAAY,MAAM,QAAQ,KAAK;AAClD,cAAI,OAAO,KAAK,YAAY,MAAM;AAClC,eAAK,OAAO;AAAA;AAGd,aAAK,MAAM,iBAAiB,KAAK,MAAM,YAAY,KAAK,MAAM,QAAQ;AACtE,aAAK,MAAM,KAAK,QAAQ,KAAK,aAAa;AAAA;AAAA,MAM5C,QAAQ,SAAU,QAAQ;AACxB,YAAI,OAAO,WAAW,aAAa;AACjC,gBAAM,IAAI,MAAM;AAAA,mBACP,CAAE,QAAO,QAAQ,QAAQ,WAAW;AAC7C,gBAAM,IAAI,MAAM;AAAA;AAGlB,gBAAQ;AAAA,eACD,QAAQ,SAAS;AAEpB,gBAAI,SAAS,OAAO,QAAS,QAAO,QAAQ,QAAQ,KAAK,UAAU,KAAK,MAAM,KAAK,WAAY,QAAO,QAAQ,SAAS,MAAM,KAAK,OAAO,QAAQ;AACjJ,iBAAK,SAAS;AACd;AAAA,eACG,QAAQ,SAAS;AACpB,gBAAI,eAAe,KAAK,WAAY,QAAO,MAAM,OAAO,OAAO,OAAO;AACtE,iBAAK,QAAQ;AACb;AAAA;AAAA;AAAA,MAON,gBAAgB,SAAU,MAAM;AAC9B,YAAI,SAAS,QAAQ,KAAK,YAAY,KAAK,WAAW;AAAG,iBAAO;AAEhE,iBAAS,IAAI,GAAG,IAAI,KAAK,YAAY,IAAI,QAAQ,KAAK;AACpD,cAAI,OAAO,KAAK,YAAY,IAAI;AAChC,cAAI,KAAK,OAAO,MAAM;AACpB,mBAAO;AAAA;AAAA;AAGX,eAAO;AAAA;AAAA,MAMT,eAAe,SAAU,MAAM;AAC7B,YAAI,SAAS,QAAQ,KAAK,YAAY,KAAK,WAAW;AAAG,iBAAO;AAEhE,iBAAS,IAAI,GAAG,IAAI,KAAK,YAAY,GAAG,QAAQ,KAAK;AACnD,cAAI,OAAO,KAAK,YAAY,GAAG;AAC/B,cAAI,KAAK,SAAS,MAAM;AACtB,mBAAO;AAAA;AAAA;AAIX,eAAO;AAAA;AAAA,MAMT,QAAQ,WAAY;AAClB,YAAI,OAAO;AAAA,UACT,MAAM,KAAK;AAAA,UACX,MAAM,KAAK;AAAA,UACX,QAAQ,KAAK,OAAO;AAAA,UACpB,MAAM,KAAK;AAAA;AAGb,eAAO;AAAA;AAAA;AAOX,SAAK,WAAW,SAAU,MAAM;AAC9B,UAAI,OAAO,IAAI;AACf,WAAK,OAAO,KAAK;AACjB,WAAK,OAAO,KAAK;AACjB,WAAK,OAAO,KAAK;AACjB,WAAK,SAAS,QAAQ,WAAW,KAAK;AAEtC,aAAO;AAAA;AAAA;AAAA;;;AC7aT;AAAA;AAAA;AAAA;AAAA,IAAO;AAAP;AAAA;AAAA,IAAO,aAAQ,IAAI,MAAM,IAAI;AAAA,MAC3B,MAAM;AACJ,cAAM,IAAI,MAAM;AAAA;AAAA;AAAA;AAAA;;;ACFpB;AAAA;AACA,WAAO,UAAU;AAGjB,QAAI,QAAQ;AACZ,QAAI,UAAU;AACd,QAAI,aAAa;AACjB,QAAI,SAAS;AACb,QAAI,OAAO;AACX,QAAI,OAAO;AAGX,QAAI,WAAW,QAAQ;AAMvB,qBAAkB,OAAO,QAAQ;AAC/B,UAAI,OAAO,UAAU,eAAe,OAAO,WAAW,aAAa;AACjE,cAAM,IAAI,MAAM;AAAA;AAGlB,WAAK,QAAQ;AACb,WAAK,SAAS;AAGd,WAAK,QAAQ;AACb,WAAK,cAAc;AACnB,WAAK,QAAQ;AACb,WAAK,YAAY;AAGjB,WAAK,UAAU;AAGf,UAAI;AACJ,WAAK,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,QAAQ,KAAK;AAC7C,YAAI,OAAO,IAAI,KAAK,QAAQ,UAAU;AACtC,aAAK,MAAM,KAAK,IAAI,KAAK;AAAA;AAI3B,WAAK,IAAI,GAAG,IAAI,KAAK,OAAO,KAAK;AAC/B,iBAAS,IAAI,KAAK,OAAO,IAAI,KAAK,SAAS,KAAK,OAAO,KAAK;AAE1D,cAAI,SAAS,KAAK,WAAW,KAAK,QAAQ,KAAK,KAAK,IAAI,KAAK;AAC7D,eAAK,QAAQ,KAAK,MAAM,IAAI,KAAK,MAAM,IAAI;AAAA;AAAA;AAAA;AAKjD,YAAQ,YAAY;AAAA,MAIlB,UAAU,SAAU,OAAO,UAAU;AACnC,YAAI,SAAS;AAGb,iBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,cAAI,KAAK,MAAM,GAAG,SAAS,SAAS;AAClC,iBAAK,MAAM,GAAG,SAAS,MAAM;AAAA,qBACpB,KAAK,MAAM,GAAG,SAAS,UAAU;AAC1C,gBAAI,aAAa,KAAK,MAAM,GAAG;AAC/B,mBAAO,KAAK;AAAA,iBACP;AACL,gBAAI;AAAU,mBAAK,MAAM,GAAG,OAAO,KAAK,WAAW,KAAK,UAAU,IAAI;AACtE,iBAAK,MAAM,GAAG;AAAA;AAAA;AAIlB,eAAO;AAAA;AAAA,MAMT,iBAAiB,SAAU,OAAO;AAChC,YAAI,SAAS;AAGb,iBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,cAAI,KAAK,MAAM,GAAG,SAAS,SAAS;AAClC,iBAAK,MAAM,GAAG,gBAAgB,MAAM;AAAA,qBAC3B,KAAK,MAAM,GAAG,SAAS,UAAU;AAC1C,gBAAI,aAAa,KAAK,MAAM,GAAG;AAC/B,mBAAO,KAAK;AAAA,iBACP;AACL,iBAAK,MAAM,GAAG;AAAA;AAAA;AAIlB,eAAO;AAAA;AAAA,MAMT,WAAW,SAAU,MAAM,UAAU,QAAQ,QAAQ;AACnD,YAAI,OAAO,WAAW,eAAe,OAAO,WAAW,KAAK,QAAQ;AAClE,gBAAM,IAAI,MAAM;AAAA;AAGlB,YAAI,cAAc,OAAO;AAGzB,YAAI;AACJ,aAAK,IAAI,KAAK,MAAM,SAAS,GAAG,KAAK,KAAK,MAAM,SAAS,KAAK,QAAQ,KAAK;AACzE,eAAK,MAAM,GAAG,UAAU,MAAM,UAAU,QAAQ,OAAO,EAAE;AAAA;AAI3D,aAAK,IAAI,KAAK,MAAM,SAAS,KAAK,SAAS,GAAG,KAAK,KAAK,OAAO,KAAK;AAClE,eAAK,MAAM,GAAG,UAAU,MAAM,UAAU;AAAA;AAAA;AAAA,MAO5C,OAAO,WAAY;AACjB,iBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,eAAK,MAAM,GAAG;AAAA;AAAA;AAAA,MAOlB,SAAS,SAAU,MAAM,IAAI,QAAQ;AACnC,YAAI,cAAc,KAAK,QAAQ,IAAI;AAEnC,iBAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,cAAI,aAAa,YAAY;AAC7B,cAAI,SAAS,IAAI;AACf,iBAAK,YAAY,KAAK;AAAA,iBACjB;AACL,iBAAK,UAAU,KAAK;AAAA;AAAA;AAIxB,eAAO;AAAA;AAAA,MAMT,YAAY,SAAU,MAAM,IAAI;AAE9B,YAAI,cAAc,SAAS,KAAK,KAAK,YAAY,KAAK;AAEtD,iBAAS,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AAC3C,cAAI,aAAa,YAAY;AAC7B,cAAI,WAAW,SAAS,QAAQ,WAAW,OAAO,IAAI;AACpD,gBAAI,WAAW,UAAU;AAAM,mBAAK,OAAO;AAC3C,wBAAY,OAAO,GAAG;AACtB;AAAA;AAAA;AAKJ,aAAK,WAAW;AAAA;AAAA,MAMlB,MAAM,SAAU,MAAM,YAAY;AAChC,YAAI,KAAK,MAAM,QAAQ,UAAU,IAAI;AACnC,gBAAM,IAAI,MAAM;AAAA,mBACP,WAAW,SAAS,MAAM;AACnC,cAAI,OAAO;AAAU,oBAAQ,KAAK;AAClC;AAAA;AAEF,aAAK,KAAK;AACV,aAAK,MAAM,KAAK;AAAA;AAAA,MAMlB,QAAQ,SAAU,YAAY;AAC5B,YAAI,QAAQ,KAAK,MAAM,QAAQ;AAC/B,YAAI,UAAU,IAAI;AAChB,gBAAM,IAAI,MAAM;AAAA;AAGlB,aAAK,MAAM,OAAO,OAAO;AACzB,mBAAW,MAAM,OAAO;AAAA;AAAA,MAM1B,QAAQ,SAAU,MAAM;AACtB,YAAI,QAAQ,KAAK,MAAM,QAAQ;AAE/B,YAAI,UAAU,IAAI;AAChB,gBAAM,IAAI,MAAM;AAAA;AAIlB,YAAI,SAAS;AAGb,aAAK,WAAW,MAAM;AAGtB,YAAI,SAAS;AACb,iBAAS,IAAI,KAAK,YAAY,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK;AACxD,cAAI,aAAa,KAAK,YAAY,GAAG;AACrC,cAAI,SAAS,SAAS,cAAc,WAAW,UAAU,QAAQ,WAAW,UAAU,MAAM;AAC1F,mBAAO,KAAK,WAAW;AAAA;AAEzB,iBAAO,KAAK,WAAW;AACvB,eAAK,WAAW,WAAW,MAAM;AAAA;AAInC,YAAI,UAAU;AACd,aAAK,IAAI,KAAK,YAAY,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK;AACrD,cAAI,aAAa,KAAK,YAAY,IAAI;AACtC,cAAI,SAAS,SAAS,cAAc,WAAW,UAAU,QAAQ,WAAW,UAAU,MAAM;AAC1F,mBAAO,KAAK,WAAW;AAAA;AAEzB,kBAAQ,KAAK,WAAW;AACxB,eAAK,WAAW,MAAM,WAAW;AAAA;AAInC,YAAI,cAAc;AAClB,aAAK,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AAClC,cAAI,QAAQ,OAAO;AACnB,mBAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,gBAAI,SAAS,QAAQ;AACrB,gBAAI,CAAC,MAAM,eAAe,SAAS;AACjC,kBAAI,OAAO,KAAK,QAAQ,OAAO;AAC/B,0BAAY,KAAK,KAAK;AAAA;AAAA;AAAA;AAM5B,aAAK,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AAClC,cAAI,YAAY,WAAW;AAAG;AAE9B,cAAI,QAAQ,OAAO;AACnB,cAAI,YAAY,KAAK,MAAM,KAAK,WAAW,YAAY;AAEvD,eAAK,KAAK,OAAO,YAAY;AAC7B,sBAAY,OAAO,WAAW;AAAA;AAIhC,aAAK,IAAI,KAAK,YAAY,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;AACvD,cAAI,QAAO,KAAK,YAAY,MAAM;AAClC,eAAK,OAAO;AAAA;AAId,aAAK,WAAW,MAAM;AAGtB,aAAK,MAAM,OAAO,OAAO;AAAA;AAAA,MAM3B,QAAQ,SAAU,QAAQ;AACxB,YAAI,OAAO,WAAW,aAAa;AACjC,gBAAM,IAAI,MAAM;AAAA;AAGlB,YAAI,GAAG;AACP,gBAAQ;AAAA,eACD,SAAS;AAEZ,gBAAI,aAAa,KAAK,YAAY,KAAK,MAAM,KAAK,WAAW,KAAK,YAAY;AAC9E,gBAAI,QAAQ,WAAW;AACvB,iBAAK,WAAW,WAAW,MAAM,WAAW;AAG5C,gBAAI,UAAU,KAAK,MAAM,QAAQ,WAAW;AAC5C,gBAAI,OAAO,IAAI,KAAK;AAGpB,iBAAK,OAAO,SAAS;AAGrB,gBAAI,WAAW,KAAK,IAAI,SAAS,KAAK,MAAM,SAAS,KAAK;AAC1D,iBAAK,MAAM,OAAO,UAAU,GAAG;AAG/B,gBAAI,WAAW,KAAK,QAAQ,WAAW,MAAM,MAAM;AACnD,gBAAI,WAAW,KAAK,QAAQ,MAAM,WAAW,IAAI;AAGjD,gBAAI,SAAS,MAAM;AACjB,mBAAK,KAAK,OAAO,KAAK,YAAY,MAAM,WAAW;AAAA;AAErD;AAAA,eACG,SAAS;AAEZ,gBAAI,KAAK,MAAM,WAAW,KAAK,QAAQ,KAAK,QAAQ;AAClD,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAIF,gBAAI,QAAQ,KAAK,MAAM,KAAK,WAAY,MAAK,MAAM,SAAS,KAAK,SAAS,KAAK,SAAS,KAAK;AAC7F,iBAAK,OAAO,KAAK,MAAM;AACvB;AAAA,eACG,SAAS;AAEZ,gBAAI,YAAY;AAChB,iBAAK,IAAI,GAAG,IAAI,KAAK,MAAM,SAAS,KAAK,QAAQ,KAAK;AACpD,kBAAI,SAAQ,KAAK,MAAM;AACvB,mBAAK,IAAI,KAAK,IAAI,IAAI,GAAG,KAAK,QAAQ,IAAI,KAAK,MAAM,QAAQ,KAAK;AAChE,oBAAI,SAAQ,KAAK,MAAM;AACvB,oBAAI,CAAC,OAAM,eAAe;AAAQ,4BAAU,KAAK,CAAC,QAAO;AAAA;AAAA;AAI7D,gBAAI,UAAU,WAAW,GAAG;AAC1B,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAGF,gBAAI,OAAO,UAAU,KAAK,MAAM,KAAK,WAAW,UAAU;AAC1D,iBAAK,QAAQ,KAAK,IAAI,KAAK;AAC3B;AAAA,eACG,SAAS;AAEZ,gBAAI,WAAW;AAEf,iBAAK,IAAI,GAAG,IAAI,KAAK,YAAY,QAAQ,KAAK;AAC5C,kBAAI,QAAO,KAAK,YAAY;AAE5B,kBAAI,MAAK,KAAK,YAAY,IAAI,SAAS,KAAK,MAAK,GAAG,YAAY,GAAG,SAAS,KAAK,KAAK,MAAM,QAAQ,MAAK,MAAM,KAAK,MAAM,QAAQ,MAAK,OAAO;AAC5I,yBAAS,KAAK;AAAA;AAAA;AAIlB,gBAAI,SAAS,WAAW,GAAG;AACzB,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAGF,gBAAI,aAAa,SAAS,KAAK,MAAM,KAAK,WAAW,SAAS;AAC9D,iBAAK,WAAW,WAAW,MAAM,WAAW;AAC5C;AAAA,eACG,SAAS;AACZ,gBAAI,iBAAiB,KAAK,YAAY,OAAO,KAAK;AAElD,gBAAI,aAAa,eAAe,KAAK,MAAM,KAAK,WAAW,eAAe;AAC1E,gBAAI,eAAe,KAAK,WAAY,QAAO,MAAM,OAAO,OAAO,OAAO;AACtE,uBAAW,UAAU;AACrB;AAAA,eACG,SAAS;AAEZ,gBAAI,QAAQ,KAAK,MAAM,KAAK,WAAY,MAAK,MAAM,SAAS,KAAK,SAAS,KAAK;AAC/E,gBAAI,OAAO,KAAK,MAAM;AACtB,iBAAK,OAAO;AACZ;AAAA,eACG,SAAS;AAEZ,gBAAI,CAAC,OAAO,gBAAgB,KAAK,QAAQ,KAAK,WAAW,KAAK,MAAM,QAAQ;AAC1E,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAGF,gBAAI,QAAQ,KAAK,MAAM,KAAK,WAAY,MAAK,MAAM,SAAU,QAAO,eAAe,IAAI,KAAK,UAAU,KAAK,SAAS,KAAK;AACzH,gBAAI,OAAO,KAAK,MAAM;AAEtB,iBAAK,OAAO;AACZ;AAAA,eACG,SAAS;AAEZ,gBAAI,WAAW;AACf,iBAAK,IAAI,KAAK,OAAO,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC/C,kBAAI,QAAO,KAAK,MAAM;AACtB,kBAAI,MAAK,YAAY,KAAK,WAAW,GAAG;AACtC,yBAAS,KAAK;AAAA;AAAA;AAIlB,gBAAI,SAAS,WAAW,GAAG;AACzB,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAIF,gBAAI,OAAO,SAAS,KAAK,MAAM,KAAK,WAAW,SAAS;AAGxD,iBAAK,QAAQ,MAAM;AACnB;AAAA,eACG,SAAS;AACZ,gBAAI,KAAK,UAAU,WAAW,GAAG;AAC/B,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAEF,gBAAI,OAAO,KAAK,UAAU,KAAK,MAAM,KAAK,WAAW,KAAK,UAAU;AACpE,iBAAK,WAAW,KAAK,MAAM,KAAK;AAChC;AAAA,eACG,SAAS;AACZ,gBAAI,iBAAiB,KAAK,YAAY,OAAO,KAAK;AAGlD,gBAAI,WAAW;AACf,iBAAK,IAAI,GAAG,IAAI,eAAe,QAAQ,KAAK;AAC1C,kBAAI,QAAO,eAAe;AAC1B,kBAAI,MAAK,UAAU,MAAM;AACvB,yBAAS,KAAK;AAAA;AAAA;AAIlB,gBAAI,SAAS,WAAW,GAAG;AACzB,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAIF,gBAAI,QAAQ,KAAK,MAAM,KAAK,WAAY,MAAK,MAAM,SAAS,KAAK,SAAS,KAAK;AAC/E,gBAAI,OAAO,KAAK,MAAM;AACtB,gBAAI,OAAO,SAAS,KAAK,MAAM,KAAK,WAAW,SAAS;AAGxD,iBAAK,KAAK,MAAM;AAChB;AAAA,eACG,SAAS;AAEZ,gBAAI,KAAK,MAAM,WAAW,GAAG;AAC3B,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAGF,gBAAI,QAAQ,KAAK,MAAM,KAAK,WAAW,KAAK,MAAM;AAClD,gBAAI,YAAY,KAAK,MAAM;AAE3B,iBAAK,OAAO;AACZ;AAAA,eACG,SAAS;AAEZ,gBAAI,YAAY;AAChB,iBAAK,IAAI,KAAK,OAAO,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC/C,kBAAI,SAAQ,KAAK,MAAM;AACvB,mBAAK,IAAI,KAAK,OAAO,IAAI,GAAG,KAAK;AAC/B,oBAAI,SAAQ,KAAK,MAAM;AACvB,oBAAI,CAAC,OAAM,eAAe;AAAQ,4BAAU,KAAK,CAAC,QAAO;AAAA;AAAA;AAI7D,gBAAI,UAAU,WAAW,GAAG;AAC1B,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAGF,gBAAI,OAAO,UAAU,KAAK,MAAM,KAAK,WAAW,UAAU;AAC1D,iBAAK,QAAQ,KAAK,IAAI,KAAK;AAC3B;AAAA,eACG,SAAS;AAEZ,gBAAI,WAAW;AAEf,iBAAK,IAAI,GAAG,IAAI,KAAK,YAAY,QAAQ,KAAK;AAC5C,kBAAI,QAAO,KAAK,YAAY;AAE5B,kBAAI,MAAK,KAAK,YAAY,IAAI,SAAS,KAAK,MAAK,GAAG,YAAY,GAAG,SAAS,KAAK,KAAK,MAAM,QAAQ,MAAK,QAAQ,KAAK,MAAM,QAAQ,MAAK,KAAK;AAC5I,yBAAS,KAAK;AAAA;AAAA;AAIlB,gBAAI,SAAS,WAAW,GAAG;AACzB,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAGF,gBAAI,aAAa,SAAS,KAAK,MAAM,KAAK,WAAW,SAAS;AAC9D,iBAAK,WAAW,WAAW,MAAM,WAAW;AAC5C;AAAA,eACG,SAAS;AAEZ,gBAAK,OAAO,gBAAgB,KAAK,MAAM,SAAS,KAAK,QAAQ,KAC1D,CAAC,OAAO,gBAAgB,KAAK,MAAM,SAAS,KAAK,QAAQ,KAAK,SAAS,GAAI;AAC5E,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC;AAAA;AAGF,gBAAI,QAAQ,KAAK,MAAM,KAAK,WAAY,MAAK,MAAM,SAAU,QAAO,eAAe,IAAI,KAAK,UAAU,KAAK,SAAS,KAAK;AACzH,gBAAI,QAAQ,KAAK,MAAM;AACvB,oBAAQ,KAAK,MAAM,KAAK,WAAY,MAAK,MAAM,SAAU,QAAO,eAAe,IAAI,KAAK,UAAU,KAAK,SAAS,KAAK;AACrH,gBAAI,QAAQ,KAAK,MAAM;AAEvB,gBAAI,WAAW,MAAM;AACrB,gBAAI,aAAa,MAAM;AAEvB,kBAAM,OAAO,MAAM;AACnB,kBAAM,SAAS,MAAM;AACrB,kBAAM,OAAO;AACb,kBAAM,SAAS;AACf;AAAA;AAAA;AAAA,MAON,OAAO,SAAU,KAAK,SAAS;AAC7B,YAAI,IAAI,GAAG,MAAM,WAAW,KAAK,SAAS,IAAI,GAAG,OAAO,WAAW,KAAK,QAAQ;AAC9E,gBAAM,IAAI,MAAM;AAAA;AAGlB,kBAAU,WAAW;AAGrB,YAAI,OAAO,QAAQ,SAAS,aAAa;AACvC,cAAI,OAAO;AAAU,oBAAQ,KAAK;AAAA;AAEpC,YAAI,OAAO,QAAQ,eAAe,aAAa;AAC7C,cAAI,OAAO;AAAU,oBAAQ,KAAK;AAAA;AAIpC,YAAI,cAAc,QAAQ,SAAS;AACnC,YAAI,OAAO,QAAQ,QAAQ,QAAQ,KAAK;AACxC,YAAI,WAAW,QAAQ,QAAQ;AAC/B,YAAI,UAAU,QAAQ,WAAW;AACjC,YAAI,WAAW,QAAQ,YAAY;AACnC,YAAI,YAAY,QAAQ,aAAa;AACrC,YAAI,aAAa,QAAQ,cAAc,QAAQ,KAAK;AAEpD,YAAI,QAAQ,KAAK;AAEjB,YAAI,YAAY,IAAI,QAAQ;AAC1B,gBAAM,IAAI,MAAM;AAAA,mBACP,OAAO,QAAQ,eAAe,eAAe,OAAO,QAAQ,UAAU,aAAa;AAC5F,gBAAM,IAAI,MAAM;AAAA,mBACP,OAAO,QAAQ,UAAU,aAAa;AAC/C,wBAAc;AAAA,mBACL,OAAO,QAAQ,eAAe,aAAa;AACpD,kBAAQ,aAAa;AAAA;AAIvB,aAAK,UAAU;AAEf,YAAI,QAAQ,eAAe;AACzB,cAAI,WAAW,KAAK,KAAM,KAAI,QAAQ,cAAc,YAAY,IAAI;AACpE,cAAI,WAAW,IAAI,MAAM,GAAG;AAC5B,cAAI,UAAU,IAAI,MAAM;AAAA;AAI1B,YAAI,cAAc;AAClB,YAAI,YAAY;AAChB,YAAI,QAAQ;AAEZ,YAAI,GAAG,GAAG;AACV,eAAO,QAAQ,eAAgB,SAAQ,eAAe,KAAK,YAAY,QAAQ,aAAa;AAC1F,cAAI,QAAQ,iBAAiB,SAAS,QAAQ,cAAc;AAAW;AAEvE;AAGA,wBAAc,WAAW,UAAU;AAGnC,cAAI,QAAQ,eAAe;AACzB,iBAAK,UAAU,UAAU,WAAW,aAAa,UAAU;AAC3D,gBAAI,QAAQ;AAAO,mBAAK;AACxB,oBAAQ,KAAK,KAAK,SAAS,MAAM;AACjC,gBAAI,QAAQ;AAAO,mBAAK;AAAA,iBACnB;AACL,oBAAQ,KAAK,UAAU,KAAK,WAAW,aAAa,UAAU;AAC9D,gBAAI,QAAQ;AAAO,mBAAK;AAAA;AAI1B,cAAI,QAAQ,SAAS;AACnB,iBAAK,GAAG,GAAG,IAAI,IAAI,QAAQ,GAAG,IAAI,KAAK,MAAM,KAAK,WAAW,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK;AAAE;AAAA;AAG7G,cAAI,QAAQ,OAAO,YAAY,QAAQ,QAAQ,GAAG;AAChD,oBAAQ,IAAI,aAAa,WAAW,SAAS,OAAO,QAAQ;AAAA;AAG9D,cAAI,QAAQ,YAAY,YAAY,QAAQ,SAAS,eAAe,GAAG;AACrE,oBAAQ,SAAS,SAAS,EAAE,OAAc;AAAA;AAAA;AAI9C,YAAI,QAAQ;AAAO,eAAK;AAExB,YAAI,SAAS;AACX,eAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,gBAAI,KAAK,MAAM,GAAG,SAAS,YAAY,KAAK,MAAM,GAAG,SAAS,YAAY;AACxE,mBAAK,MAAM,GAAG,OAAO,IAAI,KAAK;AAAA;AAAA;AAAA;AAKpC,eAAO;AAAA,UACL;AAAA,UACA,YAAY;AAAA,UACZ,MAAM,KAAK,QAAQ;AAAA;AAAA;AAAA,MAQvB,WAAW,SAAU,KAAK,WAAW,aAAa,UAAU,cAAc;AACxE,YAAI,WAAW;AACf,iBAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,cAAI,QAAQ,IAAI,GAAG;AACnB,cAAI,SAAS,IAAI,GAAG;AAEpB,cAAI,SAAS,CAAC,CAAG,MAAI,KAAK,cAAc,KAAM,IAAI,MAAO,IAAI;AAE7D,cAAI,SAAS,KAAK,SAAS,OAAO;AAClC,eAAK,UAAU,aAAa,UAAU,QAAQ;AAE9C,sBAAY,aAAa,QAAQ;AAAA;AAEnC,eAAO,WAAW,IAAI;AAAA;AAAA,MAMxB,MAAM,SAAU,KAAK,OAAO,QAAQ,KAAK,KAAK;AAE5C,YAAI;AACJ,YAAI,KAAK,SAAS;AAChB,eAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,gBAAI,KAAK,MAAM,GAAG,SAAS,YAAY,KAAK,MAAM,GAAG,SAAS,YAAY;AACxE,mBAAK,MAAM,GAAG,OAAO,IAAI,KAAK;AAAA;AAAA;AAAA;AAKpC,YAAI,QAAQ;AACZ,YAAI,QAAQ,KAAK;AAEjB,aAAK,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AAC/B,cAAI,QAAQ,IAAI,GAAG;AACnB,cAAI,SAAS,IAAI,GAAG;AACpB,cAAI,SAAS,KAAK,gBAAgB;AAClC,mBAAS,KAAK,QAAQ;AAAA;AAGxB,iBAAS,IAAI;AAEb,YAAI,UAAU;AAAA,UACZ;AAAA,UACA,MAAM,KAAK,QAAQ;AAAA;AAGrB,eAAO;AAAA;AAAA,MAMT,OAAO,SAAU,OAAO,QAAQ;AAC9B,YAAI,QAAQ;AACZ,YAAI,SAAS;AAEb,YAAI,OAAO;AAAA,UACT,OAAO;AAAA,UACP,OAAO;AAAA,UACP,aAAa,CAAC;AAAA,YACZ,MAAM;AAAA,YACN,MAAM;AAAA,YACN,SAAS;AAAA,aACR;AAAA,YACD,MAAM;AAAA,YACN,MAAM;AAAA,YACN,SAAS;AAAA;AAAA;AAIb,YAAI;AACJ,aAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,cAAI,OAAO,KAAK,MAAM;AAEtB,cAAI,KAAK,SAAS,SAAS;AACzB,gBAAI,KAAK,UAAU,GAAG;AACpB,mBAAK,YAAY,GAAG,QAAQ,KAAK;AAAA,gBAC/B,MAAM;AAAA,gBACN,QAAQ;AAAA;AAAA,mBAEL;AACL,mBAAK,YAAY,GAAG,QAAQ,KAAK;AAAA,gBAC/B,MAAM;AAAA,gBACN,QAAQ,MAAM,QAAS,MAAK,QAAQ,KAAK;AAAA;AAAA;AAG7C,iBAAK,YAAY,GAAG,QAAQ,KAAK;AAAA,cAC/B,MAAM;AAAA,cACN,QAAQ;AAAA;AAAA,qBAED,KAAK,SAAS,UAAU;AACjC,gBAAI,KAAK,WAAW,GAAG;AACrB,mBAAK,YAAY,GAAG,QAAQ,KAAK;AAAA,gBAC/B,MAAM;AAAA,gBACN,QAAQ;AAAA;AAAA,mBAEL;AACL,mBAAK,YAAY,GAAG,QAAQ,KAAK;AAAA,gBAC/B,MAAM;AAAA,gBACN,QAAQ,MAAM,QAAS,MAAK,SAAS,KAAK;AAAA;AAAA;AAG9C,iBAAK,YAAY,GAAG,QAAQ,KAAK;AAAA,cAC/B,MAAM;AAAA,cACN,QAAQ,OAAO;AAAA;AAAA;AAInB,eAAK,MAAM,KAAK;AAAA,YACd,IAAI;AAAA,YACJ,MAAM,KAAK,SAAS,WAAW,KAAK,OAAO,OAAO,KAAK,KAAK;AAAA,YAC5D,YAAY,KAAK;AAAA,YACjB,MAAM,KAAK;AAAA;AAAA;AAIf,YAAI,cAAc,KAAK,YAAY,OAAO,KAAK;AAC/C,aAAK,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AACvC,cAAI,aAAa,YAAY;AAC7B,cAAI,WAAW,SAAS,MAAM;AAC5B,iBAAK,MAAM,KAAK;AAAA,cACd,QAAQ,KAAK,MAAM,QAAQ,WAAW;AAAA,cACtC,QAAQ,KAAK,MAAM,QAAQ,WAAW;AAAA,cACtC,QAAQ,WAAW;AAAA;AAAA,iBAEhB;AAEL,gBAAI,QAAQ,KAAK,MAAM;AACvB,iBAAK,MAAM,KAAK;AAAA,cACd,IAAI;AAAA,cACJ,YAAY,WAAW,MAAM;AAAA,cAC7B,MAAM;AAAA;AAER,iBAAK,MAAM,KAAK;AAAA,cACd,QAAQ,KAAK,MAAM,QAAQ,WAAW;AAAA,cACtC,QAAQ;AAAA,cACR,QAAQ,IAAI,IAAI,WAAW;AAAA;AAE7B,iBAAK,MAAM,KAAK;AAAA,cACd,QAAQ;AAAA,cACR,QAAQ,KAAK,MAAM,QAAQ,WAAW;AAAA,cACtC,QAAQ,IAAI,IAAI,WAAW;AAAA;AAE7B,iBAAK,MAAM,KAAK;AAAA,cACd,QAAQ,KAAK,MAAM,QAAQ,WAAW;AAAA,cACtC,QAAQ;AAAA,cACR,QAAQ,WAAW,MAAM;AAAA,cACzB,MAAM;AAAA;AAAA;AAAA;AAKZ,eAAO;AAAA;AAAA,MAMT,QAAQ,WAAY;AAClB,YAAI,OAAO;AAAA,UACT,OAAO;AAAA,UACP,aAAa;AAAA,UACb,OAAO,KAAK;AAAA,UACZ,QAAQ,KAAK;AAAA,UACb,SAAS,KAAK;AAAA;AAIhB,YAAI;AACJ,aAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,eAAK,MAAM,GAAG,QAAQ;AAAA;AAGxB,aAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,cAAI,OAAO,KAAK,MAAM;AACtB,cAAI,SAAS,KAAK;AAClB,iBAAO,QAAQ;AACf,eAAK,MAAM,KAAK;AAEhB,cAAI,KAAK,YAAY,KAAK,WAAW,GAAG;AACtC,gBAAI,UAAS,KAAK,YAAY,KAAK;AACnC,oBAAO,OAAO;AACd,oBAAO,KAAK;AAEZ,oBAAO,QAAQ,KAAK,YAAY,KAAK,SAAS,OAAO,KAAK,YAAY,KAAK,MAAM,QAAQ;AACzF,iBAAK,YAAY,KAAK;AAAA;AAAA;AAI1B,aAAK,IAAI,GAAG,IAAI,KAAK,YAAY,QAAQ,KAAK;AAC5C,cAAI,OAAO,KAAK,YAAY;AAC5B,cAAI,SAAS,KAAK;AAClB,iBAAO,OAAO,KAAK,KAAK;AACxB,iBAAO,KAAK,KAAK,GAAG;AAEpB,iBAAO,QAAQ,KAAK,SAAS,OAAO,KAAK,MAAM,QAAQ;AAEvD,eAAK,YAAY,KAAK;AAAA;AAGxB,eAAO;AAAA;AAAA,MAMT,KAAK,SAAU,QAAQ;AACrB,iBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,eAAK,MAAM,GAAG,OAAO,OAAO,QAAQ,KAAK,MAAM,GAAG;AAClD,eAAK,MAAM,GAAG,SAAS,OAAO,UAAU,KAAK,MAAM,GAAG;AAAA;AAAA;AAAA,MAO1D,QAAQ,eAAgB,KAAK,SAAS;AACpC,YAAI,IAAI,GAAG,MAAM,WAAW,KAAK,SAAS,IAAI,GAAG,OAAO,WAAW,KAAK,QAAQ;AAC9E,gBAAM,IAAI,MAAM;AAAA;AAIlB,kBAAU,WAAW;AACrB,YAAI,cAAc,OAAO,QAAQ,UAAU,cAAc,QAAQ,QAAQ;AACzE,YAAI,SAAS,OAAO,QAAQ,WAAW,cAAc,QAAQ,SAAS;AACtE,YAAI,OAAO,QAAQ,QAAQ,QAAQ,KAAK;AACxC,YAAI,SAAS,QAAQ,UAAU;AAE/B,YAAI,UAAU,QAAQ;AACtB,YAAI,OAAO,YAAY,aAAa;AAClC,cAAI,OAAO,WAAW,aAAa;AACjC,sBAAU,wBAAc,OAAO;AAAA,iBAC1B;AACL,sBAAU,UAAU;AAAA;AAAA;AAIxB,YAAI,QAAQ,KAAK;AAEjB,YAAI,OAAO,QAAQ,eAAe,eAAe,OAAO,QAAQ,UAAU,aAAa;AACrF,gBAAM,IAAI,MAAM;AAAA,mBACP,OAAO,QAAQ,UAAU,aAAa;AAC/C,wBAAc;AAAA,mBACL,OAAO,QAAQ,eAAe,aAAa;AACpD,kBAAQ,aAAa;AAAA;AAGvB,YAAI;AACJ,YAAI,YAAY,GAAG;AAEjB,4BAAkB,SAAU,QAAQ;AAClC,gBAAI,QAAQ;AACZ,qBAAS,KAAI,GAAG,KAAI,QAAQ,MAAK;AAC/B,uBAAS,OAAO,KAAK,KAAK,MAAM;AAAA;AAGlC,qBAAU,QAAO,MAAM,SAAS,OAAO,QAAQ,OAAO,SAAS,OAAO,YAAY,SAAS,OAAO,MAAM,UAAU;AAClH,oBAAQ,MAAM,SAAS,YAAY;AAEnC,mBAAO,QAAQ;AAAA;AAAA,eAEZ;AAEL,cAAI,YAAY,MAAM,iBAAiB;AAGvC,cAAI,UAAU;AACd,cAAI,OAAO,WAAW,aAAa;AACjC,qBAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,sBAAQ,KAAK,IAAI,MAAM,QAAQ,KAAK,WAAW,WAAW;AAAA;AAAA,iBAEvD;AACL,qBAAS,IAAI,GAAG,IAAI,SAAS,KAAK;AAChC,sBAAQ,KAAK,IAAI,MAAM,QAAQ,QAAQ,WAAW,WAAW;AAAA;AAAA;AAIjE,4BAAkB,SAAU,YAAY;AACtC,mBAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAEtC,kBAAI,QAAQ,WAAW;AACvB,kBAAI,OAAO;AAGX,kBAAI,cAAc,SAAU,QAAQ;AAClC,oBAAI,CAAC,MAAM,QAAQ;AACjB,sBAAI,EAAE,SAAS;AAAS;AACxB;AAAA;AAGF,oBAAI,SAAS,MAAM;AAEnB,uBAAO,SAAS,QAAQ,KAAK,SAAU,QAAQ;AAC7C,yBAAO,QAAQ,CAAC;AAChB,yBAAO,SAAU,QAAO,MAAM,SAAS,OAAO,QAAQ,OAAO,SAC3D,OAAO,YAAY,SAAS,OAAO,MAAM,UAAU;AACrD,yBAAO,QAAQ,MAAM,WAAW,WAAW,YAAY,OAAO;AAC9D,8BAAY;AAAA;AAAA;AAIhB,uBAAS,KAAI,GAAG,KAAI,QAAQ,QAAQ,MAAK;AACvC,4BAAY,QAAQ;AAAA;AAAA;AAAA;AAK1B,kBAAQ,oBAAoB;AAAA;AAI9B,gBAAQ,UAAU;AAClB,YAAI,OAAO,IAAI,KAAK,KAAK,OAAO,KAAK,QAAQ,iBAAiB;AAE9D,YAAI,QAAQ;AACZ,YAAI,cAAc;AAClB,YAAI;AAEJ,eAAO,QAAQ,CAAC,eAAgB,SAAQ,eAAe,KAAK,KAAK,aAAa,QAAQ,aAAa;AACjG,cAAI,UAAU,MAAM,KAAK;AACzB,cAAI,UAAU,QAAQ;AACtB,kBAAQ,UAAW,SAAQ,MAAM,SAAS,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,YAAY,SAAS,QAAQ,MAAM,UAAU;AAEhI,cAAI,UAAU,aAAa;AACzB,0BAAc;AACd,yBAAa;AAAA;AAGf,cAAI,QAAQ,OAAO,KAAK,aAAa,QAAQ,QAAQ,GAAG;AACtD,oBAAQ,IAAI,aAAa,KAAK,YAAY,WAAW,SAAS,SAAS,CAAC;AAAA;AAG1E,cAAI,QAAQ,YAAY,KAAK,aAAa,QAAQ,SAAS,eAAe,GAAG;AAC3E,oBAAQ,SAAS,SAAS,EAAE,SAAkB,OAAO,CAAC,OAAO,WAAW,KAAK;AAAA;AAAA;AAIjF,YAAI,UAAU,GAAG;AACf,mBAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ;AAAK,oBAAQ,GAAG;AAAA;AAGtD,YAAI,OAAO,eAAe,aAAa;AACrC,eAAK,QAAQ,WAAW;AACxB,eAAK,cAAc,WAAW;AAC9B,eAAK,YAAY,WAAW;AAC5B,eAAK,QAAQ,WAAW;AAExB,cAAI,QAAQ;AAAO,iBAAK;AAAA;AAG1B,eAAO;AAAA,UACL,OAAO,CAAC;AAAA,UACR,YAAY,KAAK;AAAA,UACjB,MAAM,KAAK,QAAQ;AAAA;AAAA;AAAA,MAQvB,YAAY,WAAY;AACtB,YAAI,UAAU;AACd,YAAI,cAAc;AAClB,YAAI,SAAS;AACb,YAAI,QAAQ;AACZ,YAAI,YAAY;AAEhB,YAAI;AACJ,aAAK,IAAI,GAAG,IAAI,KAAK,OAAO,KAAK;AAC/B,cAAI,OAAO,KAAK,MAAM;AACtB,sBAAY,KAAK,KAAK;AACtB,iBAAO,KAAK,KAAK;AAAA;AAGnB,cAAM,KAAK;AAGX,aAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,eAAK,MAAM,GAAG,QAAQ;AAAA;AAGxB,aAAK,IAAI,KAAK,OAAO,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC/C,cAAI,QAAO,KAAK,MAAM;AACtB,sBAAY,KAAK,MAAK;AACtB,iBAAO,KAAK,MAAK;AAEjB,cAAI,gBAAgB,QAAQ,QAAQ,MAAK,OAAO;AAEhD,cAAI,kBAAkB,IAAI;AACxB,4BAAgB,QAAQ;AACxB,oBAAQ,KAAK,MAAK,OAAO;AACzB,sBAAU,KAAK,MAAK,OAAO;AAAA;AAG7B,cAAI,WAAW;AACf,mBAAS,IAAI,GAAG,IAAI,MAAK,YAAY,GAAG,QAAQ,KAAK;AACnD,gBAAI,OAAO,MAAK,YAAY,GAAG;AAC/B,gBAAI,cAAc,KAAK,KAAK,KAAK,YAAY,KAAK;AAElD,gBAAI,KAAK,SAAS,MAAM;AACtB,6BAAe,QAAQ,KAAK,MAAM;AAAA;AAGpC,qBAAS,KAAK;AAAA;AAGhB,cAAI,MAAK,YAAY,KAAK,QAAQ;AAChC,gBAAI,QAAO,MAAK,YAAY;AAC5B,gBAAI,eAAc,KAAK,QAAQ,MAAK;AAEpC,gBAAI,MAAK,SAAS,MAAM;AACtB,8BAAe,QAAQ,MAAK,MAAM;AAAA;AAGpC,qBAAS,KAAK;AAAA;AAGhB,cAAI,QAAQ,KAAK,QAAQ,SAAS,KAAK,YAAY,MAAK;AACxD,cAAI,QAAQ,KAAK,UAAU,oBAAoB,MAAM,CAAC,MAAK,OAAO,QAAQ,MAAK,OAAO;AACtF,gBAAM,KAAK;AACX,gBAAM,KAAK;AAAA;AAGb,YAAI,SAAS;AACb,aAAK,IAAI,KAAK,MAAM,SAAS,KAAK,QAAQ,IAAI,KAAK,MAAM,QAAQ,KAAK;AACpE,iBAAO,KAAK,KAAK;AAAA;AAGnB,iBAAS,WAAW,OAAO,KAAK;AAChC,cAAM,KAAK;AAEX,YAAI,QAAQ;AACZ,iBAAS,YAAY,UAAU;AAAA;AAC/B,iBAAS,YAAY,YAAY;AAAA;AACjC,iBAAS,YAAY,OAAO;AAAA;AAC5B,iBAAS;AAAA,EAAgC,MAAM,KAAK;AAAA;AAEpD,eAAO;AAAA;AAAA,MAMT,WAAW,WAAY;AACrB,YAAI,cAAc;AAClB,YAAI,SAAS;AACb,YAAI,QAAQ;AACZ,YAAI,WAAW;AAAA,UACb;AAAA,UAAY;AAAA,UAAQ;AAAA,UAAY;AAAA,UAAQ;AAAA,UAAQ;AAAA,UAAY;AAAA,UAC5D;AAAA,UAAY;AAAA,UAAiB;AAAA,UAAW;AAAA,UAAmB;AAAA,UAC3D;AAAA,UAAY;AAAA,UAAW;AAAA;AAGzB,cAAM,KAAK,KAAK;AAChB,cAAM,KAAK,KAAK;AAEhB,YAAI;AACJ,aAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,cAAI,OAAO,KAAK,MAAM;AACtB,eAAK,QAAQ;AACb,sBAAY,KAAK,KAAK;AACtB,iBAAO,KAAK,KAAK;AAAA;AAGnB,aAAK,IAAI,KAAK,OAAO,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC/C,cAAI,OAAO,KAAK,MAAM;AACtB,gBAAM,KAAK,KAAK;AAChB,gBAAM,KAAK,KAAK;AAChB,gBAAM,KAAK,SAAS,QAAQ,KAAK,OAAO;AAExC,gBAAM,KAAK,KAAK,YAAY,KAAK;AACjC,gBAAM,KAAK,KAAK,YAAY,KAAK,SAAS,OAAO,KAAK,KAAK,YAAY,KAAK,MAAM;AAElF,mBAAS,IAAI,GAAG,IAAI,KAAK,YAAY,GAAG,QAAQ,KAAK;AACnD,gBAAI,OAAO,KAAK,YAAY,GAAG;AAE/B,kBAAM,KAAK,KAAK,KAAK;AACrB,kBAAM,KAAK,KAAK;AAChB,kBAAM,KAAK,KAAK,SAAS,OAAO,KAAK,KAAK,MAAM;AAAA;AAGlD,gBAAM,KAAK;AAAA;AAGb,eAAO,CAAC,aAAa,QAAQ;AAAA;AAAA;AAOjC,YAAQ,WAAW,SAAU,MAAM;AACjC,UAAI,UAAU,IAAI,QAAQ,KAAK,OAAO,KAAK;AAC3C,cAAQ,UAAU,KAAK;AACvB,cAAQ,QAAQ;AAChB,cAAQ,cAAc;AAEtB,UAAI;AACJ,WAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,gBAAQ,MAAM,KAAK,KAAK,SAAS,KAAK,MAAM;AAAA;AAG9C,WAAK,IAAI,GAAG,IAAI,KAAK,YAAY,QAAQ,KAAK;AAC5C,YAAI,OAAO,KAAK,YAAY;AAE5B,YAAI,aAAa,QAAQ,QAAQ,QAAQ,MAAM,KAAK,OAAO,QAAQ,MAAM,KAAK,KAAK;AACnF,mBAAW,SAAS,KAAK;AAEzB,YAAI,KAAK,SAAS,MAAM;AACtB,kBAAQ,KAAK,QAAQ,MAAM,KAAK,QAAQ;AAAA;AAAA;AAI5C,aAAO;AAAA;AAMT,YAAQ,QAAQ,SAAU,UAAU,UAAU;AAE5C,iBAAW,QAAQ,SAAS,SAAS;AACrC,iBAAW,QAAQ,SAAS,SAAS;AAGrC,UAAI,SAAS,WAAW,SAAS,OAAO;AACtC,cAAM,IAAI,MAAM;AAAA;AAIlB,UAAI;AACJ,WAAK,IAAI,GAAG,IAAI,SAAS,YAAY,QAAQ,KAAK;AAChD,YAAI,OAAO,SAAS,YAAY;AAChC,YAAI,KAAK,KAAK,SAAS,SAAS;AAC9B,cAAI,QAAQ,SAAS,MAAM,QAAQ,KAAK;AAGxC,eAAK,OAAO,SAAS,MAAM,SAAS,MAAM,SAAS,IAAI;AAAA;AAAA;AAK3D,WAAK,IAAI,SAAS,QAAQ,GAAG,KAAK,GAAG,KAAK;AACxC,iBAAS,MAAM,OAAO,GAAG;AAAA;AAI3B,WAAK,IAAI,SAAS,MAAM,SAAS,SAAS,QAAQ,IAAI,SAAS,MAAM,QAAQ,KAAK;AAChF,iBAAS,MAAM,GAAG,OAAO;AAAA;AAI3B,eAAS,cAAc,SAAS,YAAY,OAAO,SAAS;AAC5D,eAAS,QAAQ,SAAS,MAAM,OAAO,SAAS;AAEhD,aAAO;AAAA;AAMT,YAAQ,YAAY,SAAU,UAAU,UAAU,OAAO;AACvD,UAAI,SAAS,UAAU,SAAS,SAAS,SAAS,WAAW,SAAS,QAAQ;AAC5E,cAAM,IAAI,MAAM;AAAA;AAIlB,UAAI,YAAY,IAAI,QAAQ,SAAS,OAAO,SAAS;AACrD,gBAAU,cAAc;AACxB,gBAAU,QAAQ;AAGlB,UAAI,SAAS,SAAS,SAAS;AAC/B,UAAI,SAAS,SAAS,SAAS;AAG/B,UAAI;AACJ,UAAI,SAAS,WAAW,QAAQ;AAC9B,YAAI,MAAM,KAAK,IAAI,SAAS,MAAM,QAAQ,SAAS,MAAM;AACzD,YAAI,MAAM,KAAK,IAAI,SAAS,MAAM,QAAQ,SAAS,MAAM;AACzD,eAAO,KAAK,MAAM,KAAK,WAAY,OAAM,MAAM,KAAK;AAAA,iBAC3C,SAAS,QAAQ;AAC1B,eAAO,SAAS,MAAM;AAAA,aACjB;AACL,eAAO,SAAS,MAAM;AAAA;AAIxB,UAAI,aAAa,SAAS;AAG1B,UAAI;AACJ,WAAK,IAAI,GAAG,IAAI,SAAS,MAAM,QAAQ,KAAK;AAC1C,iBAAS,MAAM,GAAG,QAAQ;AAAA;AAG5B,WAAK,IAAI,GAAG,IAAI,SAAS,MAAM,QAAQ,KAAK;AAC1C,iBAAS,MAAM,GAAG,QAAQ;AAAA;AAI5B,WAAK,IAAI,GAAG,IAAI,MAAM,KAAK;AAEzB,YAAI;AACJ,YAAI,IAAI,OAAO,YAAY;AACzB,cAAI,SAAS,KAAK;AAClB,iBAAO,UAAU,MAAM,SAAS,MAAM,KAAK,SAAS,MAAM;AAC1D,cAAI,QAAQ,SAAS,MAAM,SAAS,MAAM,KAAK,SAAS,MAAM;AAE9D,cAAI,OAAO,SAAS,eAAe,KAAK,SAAS,UAAU;AACzD,mBAAO;AAAA;AAAA,eAEJ;AACL,cAAI,KAAK,YAAY,KAAK;AACxB,mBAAO,SAAS,MAAM,SAAS,MAAM,SAAS,IAAI;AAAA,iBAC7C;AACL,mBAAO,SAAS,MAAM,SAAS,MAAM,SAAS,IAAI;AAAA;AAAA;AAItD,YAAI,UAAU,IAAI;AAClB,gBAAQ,OAAO,KAAK;AACpB,gBAAQ,SAAS,KAAK;AACtB,gBAAQ,OAAO,KAAK;AAEpB,kBAAU,MAAM,KAAK;AAAA;AAIvB,UAAI,UAAU;AACd,UAAI,UAAU;AAGd,WAAK,IAAI,GAAG,IAAI,SAAS,YAAY,QAAQ,KAAK;AAChD,YAAI,OAAO,SAAS,YAAY;AAChC,YAAI,OAAO;AAAA,UACT,QAAQ,KAAK;AAAA,UACb,MAAM,KAAK,KAAK;AAAA,UAChB,IAAI,KAAK,GAAG;AAAA,UACZ,OAAO,KAAK,SAAS,OAAO,KAAK,MAAM,QAAQ;AAAA;AAEjD,gBAAQ,WAAW,aAAa,KAAK,MAAM,KAAK,OAAO;AAAA;AAIzD,WAAK,IAAI,GAAG,IAAI,SAAS,UAAU,QAAQ,KAAK;AAC9C,YAAI,OAAO,SAAS,UAAU;AAC9B,YAAI,OAAO;AAAA,UACT,QAAQ,KAAK;AAAA,UACb,MAAM,KAAK,KAAK;AAAA,UAChB,IAAI,KAAK,GAAG;AAAA,UACZ,OAAO,KAAK,SAAS,OAAO,KAAK,MAAM,QAAQ;AAAA;AAEjD,gBAAQ,WAAW,aAAa,KAAK,MAAM,KAAK,OAAO;AAAA;AAIzD,WAAK,IAAI,GAAG,IAAI,SAAS,YAAY,QAAQ,KAAK;AAChD,YAAI,OAAO,SAAS,YAAY;AAChC,YAAI,OAAO;AAAA,UACT,QAAQ,KAAK;AAAA,UACb,MAAM,KAAK,KAAK;AAAA,UAChB,IAAI,KAAK,GAAG;AAAA,UACZ,OAAO,KAAK,SAAS,OAAO,KAAK,MAAM,QAAQ;AAAA;AAEjD,gBAAQ,WAAW,aAAa,KAAK,MAAM,KAAK,OAAO;AAAA;AAIzD,WAAK,IAAI,GAAG,IAAI,SAAS,UAAU,QAAQ,KAAK;AAC9C,YAAI,OAAO,SAAS,UAAU;AAC9B,YAAI,OAAO;AAAA,UACT,QAAQ,KAAK;AAAA,UACb,MAAM,KAAK,KAAK;AAAA,UAChB,IAAI,KAAK,GAAG;AAAA,UACZ,OAAO,KAAK,SAAS,OAAO,KAAK,MAAM,QAAQ;AAAA;AAEjD,gBAAQ,WAAW,aAAa,KAAK,MAAM,KAAK,OAAO;AAAA;AAIzD,UAAI,cAAc;AAClB,UAAI,QAAQ,OAAO,KAAK;AACxB,UAAI,QAAQ,OAAO,KAAK;AACxB,WAAK,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;AAEtC,YAAI,OAAO,QAAQ,MAAM,QAAQ,aAAa;AAC5C,cAAI,OAAO,KAAK,YAAY,MAAM,QAAQ,MAAM,MAAM,QAAQ,MAAM;AACpE,sBAAY,KAAK;AAGjB,kBAAQ,MAAM,MAAM;AAAA,mBACX,UAAU,UAAU,OAAO;AACpC,sBAAY,KAAK,QAAQ,MAAM;AAAA;AAAA;AAKnC,UAAI,UAAU,UAAU,OAAO;AAC7B,aAAK,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACjC,cAAI,OAAO,QAAQ,MAAM,QAAQ,aAAa;AAC5C,wBAAY,KAAK,QAAQ,MAAM;AAAA;AAAA;AAAA;AAMrC,WAAK,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AACvC,YAAI,WAAW,YAAY;AAC3B,YAAI,SAAS,KAAK,QAAQ,SAAS,OAAO,MAAM;AAC9C,cAAI,OAAO,UAAU,MAAM,SAAS;AACpC,cAAI,KAAK,UAAU,MAAM,SAAS;AAClC,cAAI,OAAO,UAAU,QAAQ,MAAM,IAAI;AAEvC,eAAK,SAAS,SAAS;AAEvB,cAAI,SAAS,UAAU,MAAM,SAAS,QAAQ,MAAM;AAClD,sBAAU,KAAK,UAAU,MAAM,SAAS,QAAQ;AAAA;AAAA;AAAA;AAKtD,aAAO;AAAA;AAAA;AAAA;;;AC3zCT;AAAA;AACA,WAAO,UAAU;AAGjB,QAAI,UAAU;AACd,QAAI,QAAQ;AACZ,QAAI,OAAO;AAMX,qBAAkB;AAChB,WAAK,SAAS;AAEd,WAAK,QAAQ;AACb,WAAK,cAAc;AAAA,QAAE,IAAI;AAAA,QACvB,KAAK;AAAA,QACL,MAAM;AAAA;AAAA;AAIV,UAAM,YAAY;AAAA,MAIhB,UAAU,SAAU,OAAO;AACzB,YAAI,SAAS;AAEb,YAAI,OAAO,UAAU,eAAe,MAAM,WAAW,KAAK,MAAM,QAAQ;AACtE,gBAAM,IAAI,MAAM;AAAA;AAGlB,iBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,cAAI;AACJ,cAAI,OAAO,UAAU,aAAa;AAChC,yBAAa,KAAK,MAAM,GAAG;AAAA,iBACtB;AACL,yBAAa,KAAK,MAAM,GAAG,SAAS,MAAM;AAAA;AAG5C,iBAAO,KAAK;AAAA;AAGd,eAAO;AAAA;AAAA,MAMT,WAAW,SAAU,MAAM,UAAU,QAAQ;AAC3C,YAAI,OAAO,WAAW,eAAe,OAAO,WAAW,KAAK,MAAM,QAAQ;AACxE,gBAAM,IAAI,MAAM;AAAA;AAGlB,iBAAS,IAAI,KAAK,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;AAC/C,cAAI,OAAO,WAAW,aAAa;AACjC,iBAAK,MAAM,GAAG,UAAU,MAAM,UAAU;AAAA,iBACnC;AACL,iBAAK,MAAM,GAAG,UAAU,MAAM,UAAU,MAAM,OAAO;AAAA;AAAA;AAAA;AAAA,MAQ3D,SAAS,SAAU,QAAQ,QAAQ,QAAQ;AACzC,YAAI;AACJ,YAAI,kBAAkB,SAAS,kBAAkB,MAAM;AACrD,wBAAc,KAAK,OAAO,QAAQ,QAAQ,QAAQ;AAAA,mBACzC,kBAAkB,OAAO;AAClC,wBAAc,OAAO,MAAM,MAAM,QAAQ;AAAA;AAG3C,eAAO;AAAA;AAAA,MAMT,MAAM,SAAU,aAAa,QAAQ;AACnC,aAAK,OAAO,KAAK,aAAa;AAAA;AAAA,MAMhC,KAAK,SAAU,QAAQ;AACrB,iBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,cAAI,OAAO,KAAK,MAAM;AAEtB,cAAI,gBAAgB,MAAM;AACxB,gBAAI,OAAO,OAAO,SAAS,aAAa;AACtC,mBAAK,OAAO,OAAO;AAAA;AAGrB,iBAAK,SAAS,OAAO,UAAU,KAAK;AACpC,iBAAK,OAAO,OAAO,QAAQ,KAAK;AAAA,qBACvB,gBAAgB,OAAO;AAChC,iBAAK,IAAI;AAAA;AAAA;AAAA;AAAA,MAQf,YAAY,SAAU,QAAQ,UAAU;AACtC,mBAAW,YAAY;AAGvB,YAAI,GAAG,GAAG;AACV,YAAI,kBAAkB,OAAO;AAC3B,eAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,iBAAK,IAAI,GAAG,IAAI,OAAO,MAAM,QAAQ,KAAK;AACxC,mBAAK,MAAM,GAAG,WAAW,OAAO,MAAM,IAAI;AAE1C,mBAAK,IAAI,KAAK,YAAY,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK;AACrD,oBAAI,OAAO,KAAK,YAAY,IAAI;AAEhC,oBAAI,KAAK,SAAS,KAAK,MAAM,MAAM,KAAK,OAAO,OAAO,MAAM,IAAI;AAC9D,uBAAK,YAAY,IAAI,OAAO,GAAG;AAC/B;AAAA;AAAA;AAIJ,kBAAI,UAAU;AACZ,qBAAK,IAAI,KAAK,YAAY,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK;AACpD,sBAAI,OAAO,KAAK,YAAY,GAAG;AAE/B,sBAAI,KAAK,SAAS,OAAO,MAAM,MAAM,KAAK,OAAO,KAAK,MAAM,IAAI;AAC9D,yBAAK,YAAY,GAAG,OAAO,GAAG;AAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAMD,kBAAkB,MAAM;AACjC,eAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,iBAAK,MAAM,GAAG,WAAW,QAAQ;AAEjC,iBAAK,IAAI,KAAK,YAAY,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK;AACrD,kBAAI,OAAO,KAAK,YAAY,IAAI;AAEhC,kBAAI,KAAK,SAAS,KAAK,MAAM,MAAM,KAAK,OAAO,QAAQ;AACrD,qBAAK,YAAY,IAAI,OAAO,GAAG;AAC/B;AAAA;AAAA;AAIJ,gBAAI,UAAU;AACZ,mBAAK,IAAI,KAAK,YAAY,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK;AACpD,oBAAI,OAAO,KAAK,YAAY,GAAG;AAE/B,oBAAI,KAAK,SAAS,UAAU,KAAK,OAAO,KAAK,MAAM,IAAI;AACrD,uBAAK,YAAY,GAAG,OAAO,GAAG;AAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWZ,OAAO,WAAY;AACjB,iBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,eAAK,MAAM,GAAG;AAAA;AAAA;AAAA;AAKpB,UAAM,QAAQ,SAAU,MAAM;AAE5B,UAAI,QAAQ,IAAI;AAGhB,UAAI,QAAQ,IAAI,MAAM;AAEtB,YAAM,MAAM,KAAK;AACjB,YAAM,SAAS;AAEf,YAAM,QAAQ,SAAU,MAAM,QAAQ,QAAQ;AAC5C,YAAI,gBAAgB;AAAO,iBAAO,KAAK;AACvC,iBAAS,UAAU,QAAQ,WAAW;AACtC,eAAO,KAAK,QAAQ,OAAO,QAAQ;AAAA;AAGrC,aAAO;AAAA;AAGT,UAAM,OAAO,SAAU,MAAM;AAE3B,UAAI,QAAQ,IAAI;AAGhB,UAAI,YAAY,IAAI,MAAM;AAC1B,UAAI,aAAa,IAAI,MAAM;AAC3B,UAAI,aAAa,IAAI,MAAM;AAC3B,UAAI,aAAa,IAAI,MAAM;AAC3B,UAAI,cAAc,IAAI,MAAM;AAE5B,gBAAU,IAAI;AAAA,QACZ,MAAM;AAAA;AAER,iBAAW,IAAI;AAAA,QACb,MAAM;AAAA;AAER,iBAAW,IAAI;AAAA,QACb,MAAM;AAAA;AAIR,iBAAW,QAAQ,WAAW,QAAQ,WAAW;AACjD,iBAAW,QAAQ,YAAY,QAAQ,WAAW;AAClD,iBAAW,QAAQ,YAAY,QAAQ,WAAW;AAClD,UAAI,SAAS,WAAW,QAAQ,YAAY,QAAQ,WAAW;AAC/D,UAAI,SAAS,WAAW,QAAQ,aAAa,QAAQ,WAAW;AAGhE,iBAAW,KAAK,QAAQ,QAAQ,OAAO;AACvC,iBAAW,KAAK,QAAQ,QAAQ,OAAO;AAGvC,YAAM,QAAQ,CAAC,WAAW,YAAY,YAAY,YAAY;AAG9D,YAAM,SAAS;AAEf,YAAM,QAAQ,SAAU,MAAM,QAAQ,QAAQ;AAC5C,YAAI,gBAAgB;AAAO,iBAAO,KAAK;AACvC,iBAAS,UAAU,QAAQ,WAAW;AACtC,YAAI,cAAc;AAElB,YAAI,QAAQ,KAAK,QAAQ,YAAY,QAAQ;AAC7C,sBAAc,YAAY,OAAO;AAEjC,sBAAc,YAAY,OAAO,KAAK,QAAQ,WAAW,QAAQ;AACjE,sBAAc,YAAY,OAAO,KAAK,QAAQ,YAAY,QAAQ;AAClE,sBAAc,YAAY,OAAO,KAAK,QAAQ,YAAY,QAAQ;AAElE,kBAAU,KAAK,OAAO,QAAQ,OAAO;AAErC,eAAO;AAAA;AAGT,aAAO;AAAA;AAGT,UAAM,MAAM,SAAU,MAAM;AAE1B,UAAI,QAAQ,IAAI;AAEhB,UAAI,aAAa,IAAI,MAAM;AAC3B,UAAI,oBAAoB,IAAI,MAAM;AAClC,UAAI,YAAY,IAAI,MAAM;AAC1B,UAAI,aAAa,IAAI,MAAM;AAC3B,UAAI,SAAS,IAAI,MAAM;AACvB,UAAI,iBAAiB,IAAI,MAAM;AAE/B,qBAAe,IAAI;AAAA,QACjB,MAAM;AAAA,QACN,QAAQ,QAAQ,WAAW;AAAA,QAC3B,MAAM;AAAA;AAER,iBAAW,IAAI;AAAA,QACb,QAAQ,QAAQ,WAAW;AAAA;AAE7B,wBAAkB,IAAI;AAAA,QACpB,MAAM;AAAA,QACN,QAAQ,QAAQ,WAAW;AAAA,QAC3B,MAAM;AAAA;AAER,iBAAW,IAAI;AAAA,QACb,MAAM;AAAA;AAER,gBAAU,IAAI;AAAA,QACZ,MAAM;AAAA;AAIR,qBAAe,QAAQ,YAAY,QAAQ,WAAW;AAGtD,iBAAW,QAAQ,mBAAmB,QAAQ,WAAW,YAAY;AAGrE,qBAAe,QAAQ,WAAW,QAAQ,WAAW;AAGrD,UAAI,QAAQ,eAAe,QAAQ,YAAY,QAAQ,WAAW;AAElE,gBAAU,KAAK,OAAO,QAAQ,OAAO;AAGrC,UAAI,UAAU,eAAe,QAAQ,QAAQ,QAAQ,WAAW;AAChE,UAAI,UAAU,WAAW,QAAQ,QAAQ,QAAQ,WAAW;AAE5D,iBAAW,KAAK,SAAS,QAAQ,OAAO;AACxC,wBAAkB,KAAK,SAAS,QAAQ,OAAO;AAG/C,aAAO,QAAQ,gBAAgB,QAAQ,WAAW,YAAY;AAG9D,YAAM,QAAQ,CAAC,YAAY,mBAAmB,WAAW,YAAY,QAAQ;AAE7E,YAAM,SAAS;AAEf,YAAM,QAAQ,SAAU,MAAM,QAAQ,QAAQ;AAC5C,YAAI,gBAAgB;AAAO,iBAAO,KAAK;AACvC,iBAAS,UAAU,QAAQ,WAAW;AACtC,YAAI,cAAc;AAElB,sBAAc,YAAY,OAAO,KAAK,QAAQ,YAAY,QAAQ;AAClE,sBAAc,YAAY,OAAO,KAAK,QAAQ,WAAW,QAAQ;AACjE,sBAAc,YAAY,OAAO,KAAK,QAAQ,YAAY,QAAQ;AAElE,eAAO;AAAA;AAGT,aAAO;AAAA;AAGT,UAAM,SAAS,SAAU,MAAM,QAAQ;AAErC,UAAI,QAAQ,IAAI;AAGhB,UAAI,WAAW;AACf,UAAI;AACJ,WAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B,YAAI,QAAQ,IAAI,MAAM;AAEtB,cAAM,IAAI;AAAA,UACR,QAAQ,QAAQ,WAAW;AAAA,UAC3B,MAAM;AAAA,UACN,MAAM;AAAA;AAGR,YAAI,YAAY,MAAM;AACpB,mBAAS,QAAQ,OAAO,QAAQ,WAAW,YAAY;AAAA;AAGzD,cAAM,MAAM,KAAK;AACjB,mBAAW;AAAA;AAGb,YAAM,MAAM;AAEZ,WAAK,IAAI,GAAG,IAAI,MAAM,MAAM,QAAQ,KAAK;AACvC,cAAM,MAAM,GAAG,MAAM;AAAA;AAIvB,UAAI,cAAc,IAAI,MAAM;AAC5B,eAAS,SAAS,MAAM,OAAO;AAC7B,oBAAY,QAAQ,YAAY,MAAM,OAAO,MAAM,MAAM,OAAO;AAAA;AAElE,YAAM,SAAS;AAEf,YAAM,QAAQ,SAAU,MAAM,QAAQ,QAAQ;AAC5C,YAAI,gBAAgB;AAAO,iBAAO,KAAK;AACvC,iBAAS,UAAU,QAAQ,WAAW;AAEtC,YAAI,KAAK,MAAM,WAAW,MAAM,MAAM,MAAM,MAAM,SAAS,GAAG,MAAM,QAAQ;AAC1E,gBAAM,IAAI,MAAM;AAAA;AAGlB,eAAO,KAAK,QAAQ,MAAM,MAAM,MAAM,MAAM,SAAS,IAAI,QAAQ,WAAW,YAAY;AAAA;AAG1F,aAAO;AAAA;AAAA;AAAA;;;ACxXT;AAAA;AACA,WAAO,UAAU;AAGjB,QAAI,UAAU;AACd,QAAI,SAAS;AACb,QAAI,QAAQ;AACZ,QAAI,OAAO;AAMX,mBAAgB,MAAM;AACpB,WAAK,QAAQ;AACb,WAAK,cAAc;AAAA,QACjB,IAAI;AAAA,QACJ,KAAK;AAAA,QACL,MAAM;AAAA;AAGR,eAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC7B,aAAK,MAAM,KAAK,IAAI;AAAA;AAAA;AAIxB,UAAM,YAAY;AAAA,MAIhB,UAAU,SAAU,OAAO;AACzB,YAAI,SAAS;AAEb,YAAI,OAAO,UAAU,eAAe,MAAM,WAAW,KAAK,MAAM,QAAQ;AACtE,gBAAM,IAAI,MAAM;AAAA;AAGlB,iBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,cAAI;AACJ,cAAI,OAAO,UAAU,aAAa;AAChC,yBAAa,KAAK,MAAM,GAAG;AAAA,iBACtB;AACL,yBAAa,KAAK,MAAM,GAAG,SAAS,MAAM;AAAA;AAG5C,iBAAO,KAAK;AAAA;AAGd,eAAO;AAAA;AAAA,MAMT,WAAW,SAAU,MAAM,UAAU,QAAQ;AAC3C,YAAI,OAAO,WAAW,eAAe,OAAO,WAAW,KAAK,MAAM,QAAQ;AACxE,gBAAM,IAAI,MAAM;AAAA;AAGlB,iBAAS,IAAI,KAAK,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;AAC/C,cAAI,OAAO,WAAW,aAAa;AACjC,iBAAK,MAAM,GAAG,UAAU,MAAM,UAAU;AAAA,iBACnC;AACL,iBAAK,MAAM,GAAG,UAAU,MAAM,UAAU,MAAM,OAAO;AAAA;AAAA;AAAA;AAAA,MAQ3D,SAAS,SAAU,QAAQ,QAAQ,QAAQ;AACzC,YAAI,cAAc;AAClB,YAAI,GAAG;AACP,YAAI,kBAAkB,OAAO;AAC3B,cAAI,OAAO,WAAW,aAAa;AACjC,gBAAI,SAAS,QAAQ;AACnB,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC,uBAAS,QAAQ,WAAW;AAAA,mBACvB;AACL,kBAAI,OAAO;AAAU,wBAAQ,KAAK;AAClC,uBAAS,QAAQ,WAAW;AAAA;AAAA;AAGhC,cAAI,WAAW,QAAQ,WAAW,cAAc,WAAW,QAAQ,WAAW,aAAa;AACzF,iBAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,mBAAK,IAAI,GAAG,IAAI,OAAO,MAAM,QAAQ,KAAK;AACxC,oBAAI,WAAW,QAAQ,WAAW,eAAe,KAAK,MAAM,OAAO,OAAO,MAAM;AAAI;AACpF,oBAAI,aAAa,KAAK,MAAM,GAAG,QAAQ,OAAO,MAAM,IAAI;AACxD,qBAAK,YAAY,IAAI,KAAK,WAAW;AACrC,uBAAO,YAAY,GAAG,KAAK,WAAW;AACtC,4BAAY,KAAK,WAAW;AAAA;AAAA;AAAA,qBAGvB,WAAW,QAAQ,WAAW,YAAY;AACnD,gBAAI,KAAK,MAAM,WAAW,OAAO,MAAM,QAAQ;AAC7C,oBAAM,IAAI,MAAM;AAAA;AAGlB,iBAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,kBAAI,aAAa,KAAK,MAAM,GAAG,QAAQ,OAAO,MAAM,IAAI;AACxD,mBAAK,YAAY,KAAK,KAAK,WAAW;AACtC,0BAAY,KAAK,WAAW;AAAA;AAAA;AAAA,mBAGvB,kBAAkB,OAAO;AAClC,wBAAc,OAAO,MAAM,MAAM,QAAQ;AAAA,mBAChC,kBAAkB,MAAM;AACjC,eAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,gBAAI,aAAa,KAAK,MAAM,GAAG,QAAQ,QAAQ;AAC/C,iBAAK,YAAY,IAAI,KAAK,WAAW;AACrC,wBAAY,KAAK,WAAW;AAAA;AAAA;AAIhC,eAAO;AAAA;AAAA,MAMT,MAAM,SAAU,aAAa,QAAQ;AACnC,YAAI,OAAO,WAAW,aAAa;AACjC,gBAAM,IAAI,MAAM;AAAA;AAGlB,YAAI,CAAC,MAAM,QAAQ,cAAc;AAC/B,wBAAc,CAAC;AAAA;AAGjB,YAAI,SAAS;AACb,YAAI,SAAS;AAEb,YAAI,GAAG;AACP,aAAK,IAAI,GAAG,IAAI,YAAY,QAAQ,KAAK;AACvC,cAAI,aAAa,YAAY;AAC7B,cAAI,CAAC,OAAO,SAAS,WAAW;AAAO,mBAAO,KAAK,WAAW;AAC9D,cAAI,CAAC,OAAO,SAAS,WAAW;AAAK,mBAAO,KAAK,WAAW;AAAA;AAG9D,gBAAQ;AAAA,eACD,QAAQ,OAAO;AAClB,iBAAK,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AAClC,kBAAI,OAAO,OAAO;AAClB,kBAAI,QAAQ,KAAK,MAAM,IAAI,KAAK,MAAM;AAEtC,mBAAK,IAAI,GAAG,IAAI,KAAK,YAAY,GAAG,QAAQ,KAAK;AAC/C,oBAAI,OAAO,KAAK,YAAY,GAAG;AAC/B,oBAAI,YAAY,SAAS,OAAO;AAC9B,wBAAM,KAAK;AAAA;AAAA;AAAA;AAIjB;AAAA,eACG,QAAQ,OAAO;AAClB,iBAAK,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AAClC,kBAAI,OAAO,OAAO;AAClB,kBAAI,QAAQ,KAAK,MAAM,IAAI,KAAK,MAAM;AAEtC,mBAAK,IAAI,GAAG,IAAI,KAAK,YAAY,IAAI,QAAQ,KAAK;AAChD,oBAAI,OAAO,KAAK,YAAY,IAAI;AAChC,oBAAI,YAAY,SAAS,OAAO;AAC9B,wBAAM,KAAK;AAAA;AAAA;AAAA;AAIjB;AAAA,eACG,QAAQ,OAAO;AAClB,iBAAK,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AAClC,kBAAI,OAAO,OAAO;AAClB,kBAAI,QAAQ,KAAK,MAAM,IAAI,KAAK,MAAM;AAEtC,kBAAI,YAAY,SAAS,KAAK,YAAY,OAAO;AAC/C,sBAAM,KAAK,KAAK,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA,MAStC,KAAK,SAAU,QAAQ;AACrB,iBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,cAAI,OAAO,OAAO,SAAS,aAAa;AACtC,iBAAK,MAAM,GAAG,OAAO,OAAO;AAAA;AAG9B,eAAK,MAAM,GAAG,SAAS,OAAO,UAAU,KAAK,MAAM,GAAG;AACtD,eAAK,MAAM,GAAG,OAAO,OAAO,QAAQ,KAAK,MAAM,GAAG;AAAA;AAAA;AAAA,MAOtD,YAAY,SAAU,QAAQ,UAAU;AACtC,mBAAW,YAAY;AAGvB,YAAI,GAAG,GAAG;AACV,YAAI,kBAAkB,OAAO;AAC3B,eAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,iBAAK,IAAI,GAAG,IAAI,OAAO,MAAM,QAAQ,KAAK;AACxC,mBAAK,MAAM,GAAG,WAAW,OAAO,MAAM,IAAI;AAE1C,mBAAK,IAAI,KAAK,YAAY,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK;AACrD,oBAAI,QAAO,KAAK,YAAY,IAAI;AAEhC,oBAAI,MAAK,SAAS,KAAK,MAAM,MAAM,MAAK,OAAO,OAAO,MAAM,IAAI;AAC9D,uBAAK,YAAY,IAAI,OAAO,GAAG;AAC/B;AAAA;AAAA;AAIJ,kBAAI,UAAU;AACZ,qBAAK,IAAI,KAAK,YAAY,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK;AACpD,sBAAI,QAAO,KAAK,YAAY,GAAG;AAE/B,sBAAI,MAAK,SAAS,OAAO,MAAM,MAAM,MAAK,OAAO,KAAK,MAAM,IAAI;AAC9D,yBAAK,YAAY,GAAG,OAAO,GAAG;AAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAMD,kBAAkB,MAAM;AACjC,eAAK,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AACtC,iBAAK,MAAM,GAAG,WAAW,QAAQ;AAEjC,iBAAK,IAAI,KAAK,YAAY,IAAI,SAAS,GAAG,KAAK,GAAG,KAAK;AACrD,kBAAI,QAAO,KAAK,YAAY,IAAI;AAEhC,kBAAI,MAAK,SAAS,KAAK,MAAM,MAAM,MAAK,OAAO,QAAQ;AACrD,qBAAK,YAAY,IAAI,OAAO,GAAG;AAC/B;AAAA;AAAA;AAIJ,gBAAI,UAAU;AACZ,mBAAK,IAAI,KAAK,YAAY,GAAG,SAAS,GAAG,KAAK,GAAG,KAAK;AACpD,oBAAI,OAAO,KAAK,YAAY,GAAG;AAE/B,oBAAI,KAAK,SAAS,UAAU,KAAK,OAAO,KAAK,MAAM,IAAI;AACrD,uBAAK,YAAY,GAAG,OAAO,GAAG;AAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAWZ,OAAO,WAAY;AACjB,iBAAS,IAAI,GAAG,IAAI,KAAK,MAAM,QAAQ,KAAK;AAC1C,eAAK,MAAM,GAAG;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACnQpB;AAAA;AACA,QAAI,UAAU;AACd,QAAI,UAAU;AACd,QAAI,QAAQ;AACZ,QAAI,QAAQ;AACZ,QAAI,OAAO;AAMX,QAAI,YAAY;AAAA,MAId,WAAW,SAAU,MAAM;AAEzB,YAAI,UAAU,IAAI,QAAQ,GAAG;AAG7B,YAAI,QAAQ;AAEZ,YAAI;AACJ,aAAK,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AAChC,cAAI;AACJ,cAAI,KAAK,cAAc,OAAO;AAC5B,iBAAK,IAAI,GAAG,IAAI,KAAK,GAAG,MAAM,QAAQ,KAAK;AACzC,oBAAM,KAAK,KAAK,GAAG,MAAM;AAAA;AAAA,qBAElB,KAAK,cAAc,OAAO;AACnC,iBAAK,IAAI,GAAG,IAAI,KAAK,GAAG,MAAM,QAAQ,KAAK;AACzC,uBAAS,IAAI,GAAG,IAAI,KAAK,GAAG,MAAM,GAAG,MAAM,QAAQ,KAAK;AACtD,sBAAM,KAAK,KAAK,GAAG,MAAM,GAAG,MAAM;AAAA;AAAA;AAAA,qBAG7B,KAAK,cAAc,MAAM;AAClC,kBAAM,KAAK,KAAK;AAAA;AAAA;AAKpB,YAAI,SAAS;AACb,YAAI,UAAU;AACd,aAAK,IAAI,MAAM,SAAS,GAAG,KAAK,GAAG,KAAK;AACtC,cAAI,MAAM,GAAG,SAAS,YAAY,MAAM,GAAG,YAAY,IAAI,SAAS,MAAM,GAAG,YAAY,MAAM,WAAW,GAAG;AAC3G,kBAAM,GAAG,OAAO;AAChB,oBAAQ;AACR,oBAAQ,KAAK,MAAM;AACnB,kBAAM,OAAO,GAAG;AAAA,qBACP,MAAM,GAAG,SAAS,WAAW,CAAC,MAAM,GAAG,YAAY,GAAG,QAAQ;AACvE,kBAAM,GAAG,OAAO;AAChB,oBAAQ;AACR,mBAAO,KAAK,MAAM;AAClB,kBAAM,OAAO,GAAG;AAAA;AAAA;AAKpB,gBAAQ,OAAO,OAAO,OAAO,OAAO;AAEpC,YAAI,QAAQ,UAAU,KAAK,QAAQ,WAAW,GAAG;AAC/C,gBAAM,IAAI,MAAM;AAAA;AAGlB,aAAK,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACjC,cAAI;AACJ,eAAK,IAAI,GAAG,IAAI,MAAM,GAAG,YAAY,IAAI,QAAQ,KAAK;AACpD,oBAAQ,YAAY,KAAK,MAAM,GAAG,YAAY,IAAI;AAAA;AAEpD,eAAK,IAAI,GAAG,IAAI,MAAM,GAAG,YAAY,MAAM,QAAQ,KAAK;AACtD,oBAAQ,MAAM,KAAK,MAAM,GAAG,YAAY,MAAM;AAAA;AAEhD,cAAI,MAAM,GAAG,YAAY,KAAK,WAAW,GAAG;AAC1C,oBAAQ,UAAU,KAAK,MAAM,GAAG,YAAY;AAAA;AAAA;AAIhD,gBAAQ,QAAQ;AAEhB,eAAO;AAAA;AAAA,MAMT,YAAY,WAAY;AAEtB,YAAI,SAAS,MAAM,UAAU,MAAM,KAAK;AACxC,YAAI,OAAO,SAAS,GAAG;AACrB,gBAAM,IAAI,MAAM;AAAA;AAIlB,YAAI,QAAQ;AACZ,cAAM,KAAK,IAAI,MAAM,OAAO;AAE5B,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,cAAI,QAAQ,OAAO;AACnB,kBAAQ,IAAI,MAAM;AAClB,gBAAM,KAAK;AACX,gBAAM,IAAI,GAAG,QAAQ,MAAM,IAAI,QAAQ,WAAW;AAAA;AAIpD,eAAO,UAAU,UAAU;AAAA;AAAA,MAM7B,QAAQ,SAAU,OAAO,QAAQ,QAAQ,SAAS;AAChD,kBAAU,WAAW;AAErB,YAAI,cAAc,QAAQ,eAAe,SAAS;AAClD,YAAI,kBAAkB,QAAQ,mBAAmB;AACjD,YAAI,kBAAkB,QAAQ,mBAAmB;AACjD,YAAI,QAAQ,QAAQ,SAAS;AAE7B,YAAI,UAAU,IAAI,QAAQ,OAAO;AAEjC,YAAI;AACJ,aAAK,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC3B,kBAAQ,OAAO,QAAQ,SAAS;AAAA;AAGlC,aAAK,IAAI,GAAG,IAAI,cAAc,QAAQ,KAAK;AACzC,kBAAQ,OAAO,QAAQ,SAAS;AAAA;AAGlC,aAAK,IAAI,GAAG,IAAI,iBAAiB,KAAK;AACpC,kBAAQ,OAAO,QAAQ,SAAS;AAAA;AAGlC,aAAK,IAAI,GAAG,IAAI,iBAAiB,KAAK;AACpC,kBAAQ,OAAO,QAAQ,SAAS;AAAA;AAGlC,aAAK,IAAI,GAAG,IAAI,OAAO,KAAK;AAC1B,kBAAQ,OAAO,QAAQ,SAAS;AAAA;AAGlC,eAAO;AAAA;AAAA,MAMT,MAAM,WAAY;AAChB,YAAI,OAAO,MAAM,UAAU,MAAM,KAAK;AACtC,YAAI,KAAK,SAAS,GAAG;AACnB,gBAAM,IAAI,MAAM;AAAA;AAGlB,YAAI,OAAO,KAAK;AAEhB,YAAI;AACJ,YAAI,OAAO,SAAS,UAAU;AAC5B,wBAAc,IAAI,MAAM;AACxB,iBAAO;AAAA,eACF;AACL,wBAAc,IAAI,MAAM,KAAK;AAAA;AAG/B,oBAAY,IAAI;AAAA,UACd,MAAM;AAAA;AAGR,YAAI,UAAU;AACd,gBAAQ,iBAAiB,KAAK,kBAAkB;AAChD,gBAAQ,iBAAiB,KAAK,kBAAkB;AAChD,gBAAQ,gBAAgB,KAAK,iBAAiB;AAC9C,gBAAQ,gBAAgB,KAAK,kBAAkB,SAAY,OAAO,KAAK;AACvE,gBAAQ,cAAc,KAAK,gBAAgB,SAAY,OAAO,KAAK;AAEnE,YAAI,aAAa,IAAI,MAAM,KAAK;AAChC,mBAAW,IAAI;AAAA,UACb,MAAM;AAAA;AAGR,YAAI,SAAS;AAEb,YAAI,QAAQ;AACZ,cAAM,KAAK;AAEX,YAAI,WAAW;AACf,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,cAAI,QAAQ,OAAO;AAGnB,cAAI,YAAY,IAAI,MAAM;AAC1B,cAAI,aAAa,IAAI,MAAM;AAC3B,cAAI,aAAa,IAAI,MAAM;AAC3B,cAAI,aAAa,IAAI,MAAM;AAC3B,cAAI,cAAc,MAAM,OAAO,SAAS,IAAI,cAAc,IAAI,MAAM;AAEpE,oBAAU,IAAI;AAAA,YACZ,MAAM;AAAA;AAER,qBAAW,IAAI;AAAA,YACb,MAAM;AAAA;AAER,qBAAW,IAAI;AAAA,YACb,MAAM;AAAA;AAIR,cAAI,QAAQ,SAAS,QAAQ,YAAY,QAAQ,WAAW;AAC5D,mBAAS,QAAQ,WAAW,QAAQ,WAAW;AAC/C,mBAAS,QAAQ,YAAY,QAAQ,WAAW;AAChD,mBAAS,QAAQ,YAAY,QAAQ,WAAW;AAGhD,qBAAW,QAAQ,WAAW,QAAQ,WAAW;AACjD,qBAAW,QAAQ,YAAY,QAAQ,WAAW;AAClD,qBAAW,QAAQ,YAAY,QAAQ,WAAW;AAClD,cAAI,SAAS,WAAW,QAAQ,YAAY,QAAQ,WAAW;AAC/D,cAAI,SAAS,WAAW,QAAQ,aAAa,QAAQ,WAAW;AAGhE,oBAAU,KAAK,OAAO,QAAQ,OAAO;AACrC,qBAAW,KAAK,QAAQ,QAAQ,OAAO;AACvC,qBAAW,KAAK,QAAQ,QAAQ,OAAO;AAGvC,cAAI,QAAQ,eAAe,IAAI,GAAG;AAChC,gBAAI,SAAQ,WAAW,QAAQ,YAAY,QAAQ,WAAW;AAC9D,sBAAU,KAAK,QAAO,QAAQ,OAAO;AAAA;AAIvC,cAAI,QAAQ,gBAAgB;AAC1B,gBAAI,SAAQ,WAAW,QAAQ,YAAY,QAAQ,WAAW;AAC9D,sBAAU,KAAK,QAAO,QAAQ,OAAO;AAAA;AAGvC,cAAI,QAAQ,gBAAgB;AAC1B,gBAAI,SAAQ,YAAY,QAAQ,YAAY,QAAQ,WAAW;AAC/D,sBAAU,KAAK,QAAO,QAAQ,OAAO;AAAA;AAGvC,cAAI,QAAQ,eAAe;AACzB,wBAAY,QAAQ,WAAW,QAAQ,WAAW;AAClD,wBAAY,QAAQ,YAAY,QAAQ,WAAW;AACnD,wBAAY,QAAQ,YAAY,QAAQ,WAAW;AAAA;AAIrD,gBAAM,KAAK;AACX,gBAAM,KAAK;AACX,gBAAM,KAAK;AACX,gBAAM,KAAK;AACX,cAAI,MAAM,OAAO,SAAS;AAAG,kBAAM,KAAK;AAExC,qBAAW;AAAA;AAIb,YAAI,QAAQ,eAAe;AACzB,qBAAW,QAAQ,aAAa,QAAQ,WAAW;AAAA;AAGrD,cAAM,KAAK;AACX,eAAO,UAAU,UAAU;AAAA;AAAA,MAM7B,KAAK,WAAY;AACf,YAAI,OAAO,MAAM,UAAU,MAAM,KAAK;AACtC,YAAI,KAAK,SAAS,GAAG;AACnB,gBAAM,IAAI,MAAM;AAAA;AAGlB,YAAI,aAAa,IAAI,MAAM,KAAK;AAChC,YAAI,cAAc,IAAI,MAAM,KAAK;AACjC,YAAI,SAAS;AAEb,YAAI,QAAQ;AACZ,cAAM,KAAK;AAEX,YAAI,WAAW;AACf,iBAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,cAAI,QAAQ,IAAI,MAAM,IAAI,OAAO;AACjC,mBAAS,QAAQ;AACjB,qBAAW;AAEX,gBAAM,KAAK;AAAA;AAGb,iBAAS,QAAQ;AACjB,cAAM,KAAK;AAEX,eAAO,UAAU,UAAU;AAAA;AAAA,MAM7B,UAAU,SAAU,MAAM;AACxB,YAAI,QAAQ,IAAI,MAAM;AACtB,YAAI,SAAS,IAAI,MAAM;AAEvB,cAAM,QAAQ,QAAQ,QAAQ,WAAW;AAEzC,cAAM,IAAI;AAAA,UACR,MAAM;AAAA;AAER,eAAO,IAAI;AAAA,UACT,QAAQ,QAAQ,WAAW;AAAA,UAC3B,MAAM;AAAA;AAGR,YAAI,UAAU,IAAI,UAAU,UAAU,CAAC,OAAO;AAE9C,eAAO;AAAA;AAAA,MAMT,MAAM,SAAU,WAAW,cAAc,YAAY,eAAe,gBAAgB;AAClF,YAAI,CAAC,MAAM,QAAQ,eAAe;AAChC,yBAAe,CAAC;AAAA;AAGlB,YAAI,QAAQ;AAEZ,YAAI,QAAQ,IAAI,MAAM,MAAM;AAC5B,YAAI,cAAc,IAAI,MAAM,OAAO,WAAW;AAC9C,YAAI,SAAS;AACb,YAAI,SAAS,IAAI,MAAM,MAAM;AAC7B,YAAI,eAAe,IAAI,MAAM,OAAO,YAAY;AAEhD,cAAM,KAAK;AACX,cAAM,KAAK;AAEX,iBAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,cAAI,cAAc,IAAI,MAAM,MAAM,aAAa;AAC/C,iBAAO,KAAK;AACZ,gBAAM,KAAK;AACX,cAAI,OAAO,OAAO,IAAI,OAAO,aAAa;AACxC,mBAAO,IAAI,GAAG,QAAQ,aAAa,QAAQ,WAAW;AAAA;AAAA;AAI1D,cAAM,KAAK;AACX,cAAM,KAAK;AAEX,cAAM,QAAQ,OAAO,IAAI,QAAQ,WAAW;AAC5C,cAAM,QAAQ,aAAa,QAAQ,WAAW,YAAY;AAC1D,oBAAY,QAAQ,OAAO,IAAI,QAAQ,WAAW;AAClD,eAAO,OAAO,SAAS,GAAG,QAAQ,QAAQ,QAAQ,WAAW;AAC7D,eAAO,QAAQ,cAAc,QAAQ,WAAW,YAAY;AAC5D,qBAAa,QAAQ,OAAO,IAAI,QAAQ,WAAW;AAEnD,cAAM,IAAI;AAAA,UACR,MAAM;AAAA;AAER,eAAO,IAAI;AAAA,UACT,MAAM;AAAA;AAGR,eAAO,UAAU,UAAU;AAAA;AAAA;AAK/B,WAAO,UAAU;AAAA;AAAA;;;AChXjB;AAAA;AAAA,QAAI,YAAY;AAAA,MACd,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,WAAW;AAAA,MACX,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,MACP,OAAO;AAAA,MACP,MAAM;AAAA,MACN,MAAM;AAAA,MACN,OAAO;AAAA;AAIT,QAAI,OAAO,WAAW,eAAe,OAAO,KAAK;AAC/C,aAAO,IAAI,WAAY;AAAE,eAAO;AAAA;AAAA;AAIlC,QAAI,OAAO,WAAW,eAAe,OAAO,SAAS;AACnD,aAAO,UAAU;AAAA;AAInB,QAAI,OAAO,WAAW,UAAU;AAC9B,MAAC,YAAY;AACX,YAAI,MAAM,OAAO;AACjB,kBAAU,QAAQ,WAAY;AAC5B,iBAAO,eAAe;AACtB,iBAAO;AAAA;AAAA;AAIX,aAAO,eAAe;AAAA;AAAA;AAAA;;;ACjCxB,IAAO,oBAAQ;", - "names": [] -} diff --git a/node_modules/.vite/p5.js b/node_modules/.vite/p5.js deleted file mode 100644 index 62ece0f..0000000 --- a/node_modules/.vite/p5.js +++ /dev/null @@ -1,17062 +0,0 @@ -import { - __commonJS, - __require -} from "./chunk-ELXAK55F.js"; - -// node_modules/p5/lib/p5.min.js -var require_p5_min = __commonJS({ - "node_modules/p5/lib/p5.min.js"(exports, module) { - !function(e) { - if (typeof exports == "object" && typeof module != "undefined") - module.exports = e(); - else if (typeof define == "function" && define.amd) - define([], e); - else { - (typeof window != "undefined" ? window : typeof global != "undefined" ? global : typeof self != "undefined" ? self : this).p5 = e(); - } - }(function() { - return function i(a, s, l) { - function u(t, e2) { - if (!s[t]) { - if (!a[t]) { - var r = typeof __require == "function" && __require; - if (!e2 && r) - return r(t, true); - if (c) - return c(t, true); - var n = new Error("Cannot find module '" + t + "'"); - throw n.code = "MODULE_NOT_FOUND", n; - } - var o = s[t] = { exports: {} }; - a[t][0].call(o.exports, function(e3) { - return u(a[t][1][e3] || e3); - }, o, o.exports, i, a, s, l); - } - return s[t].exports; - } - for (var c = typeof __require == "function" && __require, e = 0; e < l.length; e++) - u(l[e]); - return u; - }({ 1: [function(e, t, r) { - "use strict"; - r.byteLength = function(e2) { - var t2 = d(e2), r2 = t2[0], n2 = t2[1]; - return 3 * (r2 + n2) / 4 - n2; - }, r.toByteArray = function(e2) { - var t2, r2, n2 = d(e2), o2 = n2[0], i2 = n2[1], a = new c(function(e3, t3) { - return 3 * (e3 + t3) / 4 - t3; - }(o2, i2)), s2 = 0, l2 = 0 < i2 ? o2 - 4 : o2; - for (r2 = 0; r2 < l2; r2 += 4) - t2 = u[e2.charCodeAt(r2)] << 18 | u[e2.charCodeAt(r2 + 1)] << 12 | u[e2.charCodeAt(r2 + 2)] << 6 | u[e2.charCodeAt(r2 + 3)], a[s2++] = t2 >> 16 & 255, a[s2++] = t2 >> 8 & 255, a[s2++] = 255 & t2; - i2 === 2 && (t2 = u[e2.charCodeAt(r2)] << 2 | u[e2.charCodeAt(r2 + 1)] >> 4, a[s2++] = 255 & t2); - i2 === 1 && (t2 = u[e2.charCodeAt(r2)] << 10 | u[e2.charCodeAt(r2 + 1)] << 4 | u[e2.charCodeAt(r2 + 2)] >> 2, a[s2++] = t2 >> 8 & 255, a[s2++] = 255 & t2); - return a; - }, r.fromByteArray = function(e2) { - for (var t2, r2 = e2.length, n2 = r2 % 3, o2 = [], i2 = 0, a = r2 - n2; i2 < a; i2 += 16383) - o2.push(l(e2, i2, a < i2 + 16383 ? a : i2 + 16383)); - n2 == 1 ? (t2 = e2[r2 - 1], o2.push(s[t2 >> 2] + s[t2 << 4 & 63] + "==")) : n2 == 2 && (t2 = (e2[r2 - 2] << 8) + e2[r2 - 1], o2.push(s[t2 >> 10] + s[t2 >> 4 & 63] + s[t2 << 2 & 63] + "=")); - return o2.join(""); - }; - for (var s = [], u = [], c = typeof Uint8Array != "undefined" ? Uint8Array : Array, n = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", o = 0, i = n.length; o < i; ++o) - s[o] = n[o], u[n.charCodeAt(o)] = o; - function d(e2) { - var t2 = e2.length; - if (0 < t2 % 4) - throw new Error("Invalid string. Length must be a multiple of 4"); - var r2 = e2.indexOf("="); - return r2 === -1 && (r2 = t2), [r2, r2 === t2 ? 0 : 4 - r2 % 4]; - } - function l(e2, t2, r2) { - for (var n2, o2, i2 = [], a = t2; a < r2; a += 3) - n2 = (e2[a] << 16 & 16711680) + (e2[a + 1] << 8 & 65280) + (255 & e2[a + 2]), i2.push(s[(o2 = n2) >> 18 & 63] + s[o2 >> 12 & 63] + s[o2 >> 6 & 63] + s[63 & o2]); - return i2.join(""); - } - u["-".charCodeAt(0)] = 62, u["_".charCodeAt(0)] = 63; - }, {}], 2: [function(e, t, r) { - }, {}], 3: [function(e, t, r) { - arguments[4][2][0].apply(r, arguments); - }, { dup: 2 }], 4: [function(U, e, N) { - (function(d) { - "use strict"; - var n = U("base64-js"), i = U("ieee754"), e2 = typeof Symbol == "function" && typeof Symbol.for == "function" ? Symbol.for("nodejs.util.inspect.custom") : null; - N.Buffer = d, N.SlowBuffer = function(e3) { - +e3 != e3 && (e3 = 0); - return d.alloc(+e3); - }, N.INSPECT_MAX_BYTES = 50; - var r = 2147483647; - function a(e3) { - if (r < e3) - throw new RangeError('The value "' + e3 + '" is invalid for option "size"'); - var t2 = new Uint8Array(e3); - return Object.setPrototypeOf(t2, d.prototype), t2; - } - function d(e3, t2, r2) { - if (typeof e3 != "number") - return o(e3, t2, r2); - if (typeof t2 == "string") - throw new TypeError('The "string" argument must be of type string. Received type number'); - return l(e3); - } - function o(e3, t2, r2) { - if (typeof e3 == "string") - return function(e4, t3) { - typeof t3 == "string" && t3 !== "" || (t3 = "utf8"); - if (!d.isEncoding(t3)) - throw new TypeError("Unknown encoding: " + t3); - var r3 = 0 | f(e4, t3), n3 = a(r3), o3 = n3.write(e4, t3); - o3 !== r3 && (n3 = n3.slice(0, o3)); - return n3; - }(e3, t2); - if (ArrayBuffer.isView(e3)) - return u(e3); - if (e3 == null) - throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type " + typeof e3); - if (R(e3, ArrayBuffer) || e3 && R(e3.buffer, ArrayBuffer)) - return function(e4, t3, r3) { - if (t3 < 0 || e4.byteLength < t3) - throw new RangeError('"offset" is outside of buffer bounds'); - if (e4.byteLength < t3 + (r3 || 0)) - throw new RangeError('"length" is outside of buffer bounds'); - var n3; - n3 = t3 === void 0 && r3 === void 0 ? new Uint8Array(e4) : r3 === void 0 ? new Uint8Array(e4, t3) : new Uint8Array(e4, t3, r3); - return Object.setPrototypeOf(n3, d.prototype), n3; - }(e3, t2, r2); - if (typeof e3 == "number") - throw new TypeError('The "value" argument must not be of type number. Received type number'); - var n2 = e3.valueOf && e3.valueOf(); - if (n2 != null && n2 !== e3) - return d.from(n2, t2, r2); - var o2 = function(e4) { - if (d.isBuffer(e4)) { - var t3 = 0 | c(e4.length), r3 = a(t3); - return r3.length === 0 || e4.copy(r3, 0, 0, t3), r3; - } - if (e4.length !== void 0) - return typeof e4.length != "number" || D(e4.length) ? a(0) : u(e4); - if (e4.type === "Buffer" && Array.isArray(e4.data)) - return u(e4.data); - }(e3); - if (o2) - return o2; - if (typeof Symbol != "undefined" && Symbol.toPrimitive != null && typeof e3[Symbol.toPrimitive] == "function") - return d.from(e3[Symbol.toPrimitive]("string"), t2, r2); - throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type " + typeof e3); - } - function s(e3) { - if (typeof e3 != "number") - throw new TypeError('"size" argument must be of type number'); - if (e3 < 0) - throw new RangeError('The value "' + e3 + '" is invalid for option "size"'); - } - function l(e3) { - return s(e3), a(e3 < 0 ? 0 : 0 | c(e3)); - } - function u(e3) { - for (var t2 = e3.length < 0 ? 0 : 0 | c(e3.length), r2 = a(t2), n2 = 0; n2 < t2; n2 += 1) - r2[n2] = 255 & e3[n2]; - return r2; - } - function c(e3) { - if (r <= e3) - throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x" + r.toString(16) + " bytes"); - return 0 | e3; - } - function f(e3, t2) { - if (d.isBuffer(e3)) - return e3.length; - if (ArrayBuffer.isView(e3) || R(e3, ArrayBuffer)) - return e3.byteLength; - if (typeof e3 != "string") - throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type ' + typeof e3); - var r2 = e3.length, n2 = 2 < arguments.length && arguments[2] === true; - if (!n2 && r2 === 0) - return 0; - for (var o2 = false; ; ) - switch (t2) { - case "ascii": - case "latin1": - case "binary": - return r2; - case "utf8": - case "utf-8": - return P(e3).length; - case "ucs2": - case "ucs-2": - case "utf16le": - case "utf-16le": - return 2 * r2; - case "hex": - return r2 >>> 1; - case "base64": - return k(e3).length; - default: - if (o2) - return n2 ? -1 : P(e3).length; - t2 = ("" + t2).toLowerCase(), o2 = true; - } - } - function h(e3, t2, r2) { - var n2 = e3[t2]; - e3[t2] = e3[r2], e3[r2] = n2; - } - function p(e3, t2, r2, n2, o2) { - if (e3.length === 0) - return -1; - if (typeof r2 == "string" ? (n2 = r2, r2 = 0) : 2147483647 < r2 ? r2 = 2147483647 : r2 < -2147483648 && (r2 = -2147483648), D(r2 = +r2) && (r2 = o2 ? 0 : e3.length - 1), r2 < 0 && (r2 = e3.length + r2), r2 >= e3.length) { - if (o2) - return -1; - r2 = e3.length - 1; - } else if (r2 < 0) { - if (!o2) - return -1; - r2 = 0; - } - if (typeof t2 == "string" && (t2 = d.from(t2, n2)), d.isBuffer(t2)) - return t2.length === 0 ? -1 : y(e3, t2, r2, n2, o2); - if (typeof t2 == "number") - return t2 &= 255, typeof Uint8Array.prototype.indexOf == "function" ? o2 ? Uint8Array.prototype.indexOf.call(e3, t2, r2) : Uint8Array.prototype.lastIndexOf.call(e3, t2, r2) : y(e3, [t2], r2, n2, o2); - throw new TypeError("val must be string, number or Buffer"); - } - function y(e3, t2, r2, n2, o2) { - var i2, a2 = 1, s2 = e3.length, l2 = t2.length; - if (n2 !== void 0 && ((n2 = String(n2).toLowerCase()) === "ucs2" || n2 === "ucs-2" || n2 === "utf16le" || n2 === "utf-16le")) { - if (e3.length < 2 || t2.length < 2) - return -1; - s2 /= a2 = 2, l2 /= 2, r2 /= 2; - } - function u2(e4, t3) { - return a2 === 1 ? e4[t3] : e4.readUInt16BE(t3 * a2); - } - if (o2) { - var c2 = -1; - for (i2 = r2; i2 < s2; i2++) - if (u2(e3, i2) === u2(t2, c2 === -1 ? 0 : i2 - c2)) { - if (c2 === -1 && (c2 = i2), i2 - c2 + 1 === l2) - return c2 * a2; - } else - c2 !== -1 && (i2 -= i2 - c2), c2 = -1; - } else - for (s2 < r2 + l2 && (r2 = s2 - l2), i2 = r2; 0 <= i2; i2--) { - for (var d2 = true, f2 = 0; f2 < l2; f2++) - if (u2(e3, i2 + f2) !== u2(t2, f2)) { - d2 = false; - break; - } - if (d2) - return i2; - } - return -1; - } - function m(e3, t2, r2, n2) { - r2 = Number(r2) || 0; - var o2 = e3.length - r2; - n2 ? o2 < (n2 = Number(n2)) && (n2 = o2) : n2 = o2; - var i2 = t2.length; - i2 / 2 < n2 && (n2 = i2 / 2); - for (var a2 = 0; a2 < n2; ++a2) { - var s2 = parseInt(t2.substr(2 * a2, 2), 16); - if (D(s2)) - return a2; - e3[r2 + a2] = s2; - } - return a2; - } - function g(e3, t2, r2, n2) { - return A(function(e4) { - for (var t3 = [], r3 = 0; r3 < e4.length; ++r3) - t3.push(255 & e4.charCodeAt(r3)); - return t3; - }(t2), e3, r2, n2); - } - function v(e3, t2, r2, n2) { - return A(function(e4, t3) { - for (var r3, n3, o2, i2 = [], a2 = 0; a2 < e4.length && !((t3 -= 2) < 0); ++a2) - r3 = e4.charCodeAt(a2), n3 = r3 >> 8, o2 = r3 % 256, i2.push(o2), i2.push(n3); - return i2; - }(t2, e3.length - r2), e3, r2, n2); - } - function b(e3, t2, r2) { - return t2 === 0 && r2 === e3.length ? n.fromByteArray(e3) : n.fromByteArray(e3.slice(t2, r2)); - } - function _(e3, t2, r2) { - r2 = Math.min(e3.length, r2); - for (var n2 = [], o2 = t2; o2 < r2; ) { - var i2, a2, s2, l2, u2 = e3[o2], c2 = null, d2 = 239 < u2 ? 4 : 223 < u2 ? 3 : 191 < u2 ? 2 : 1; - if (o2 + d2 <= r2) - switch (d2) { - case 1: - u2 < 128 && (c2 = u2); - break; - case 2: - (192 & (i2 = e3[o2 + 1])) == 128 && 127 < (l2 = (31 & u2) << 6 | 63 & i2) && (c2 = l2); - break; - case 3: - i2 = e3[o2 + 1], a2 = e3[o2 + 2], (192 & i2) == 128 && (192 & a2) == 128 && 2047 < (l2 = (15 & u2) << 12 | (63 & i2) << 6 | 63 & a2) && (l2 < 55296 || 57343 < l2) && (c2 = l2); - break; - case 4: - i2 = e3[o2 + 1], a2 = e3[o2 + 2], s2 = e3[o2 + 3], (192 & i2) == 128 && (192 & a2) == 128 && (192 & s2) == 128 && 65535 < (l2 = (15 & u2) << 18 | (63 & i2) << 12 | (63 & a2) << 6 | 63 & s2) && l2 < 1114112 && (c2 = l2); - } - c2 === null ? (c2 = 65533, d2 = 1) : 65535 < c2 && (c2 -= 65536, n2.push(c2 >>> 10 & 1023 | 55296), c2 = 56320 | 1023 & c2), n2.push(c2), o2 += d2; - } - return function(e4) { - var t3 = e4.length; - if (t3 <= x) - return String.fromCharCode.apply(String, e4); - var r3 = "", n3 = 0; - for (; n3 < t3; ) - r3 += String.fromCharCode.apply(String, e4.slice(n3, n3 += x)); - return r3; - }(n2); - } - N.kMaxLength = r, (d.TYPED_ARRAY_SUPPORT = function() { - try { - var e3 = new Uint8Array(1), t2 = { foo: function() { - return 42; - } }; - return Object.setPrototypeOf(t2, Uint8Array.prototype), Object.setPrototypeOf(e3, t2), e3.foo() === 42; - } catch (e4) { - return false; - } - }()) || typeof console == "undefined" || typeof console.error != "function" || console.error("This browser lacks typed array (Uint8Array) support which is required by `buffer` v5.x. Use `buffer` v4.x if you require old browser support."), Object.defineProperty(d.prototype, "parent", { enumerable: true, get: function() { - if (d.isBuffer(this)) - return this.buffer; - } }), Object.defineProperty(d.prototype, "offset", { enumerable: true, get: function() { - if (d.isBuffer(this)) - return this.byteOffset; - } }), typeof Symbol != "undefined" && Symbol.species != null && d[Symbol.species] === d && Object.defineProperty(d, Symbol.species, { value: null, configurable: true, enumerable: false, writable: false }), d.poolSize = 8192, d.from = function(e3, t2, r2) { - return o(e3, t2, r2); - }, Object.setPrototypeOf(d.prototype, Uint8Array.prototype), Object.setPrototypeOf(d, Uint8Array), d.alloc = function(e3, t2, r2) { - return o2 = t2, i2 = r2, s(n2 = e3), n2 <= 0 ? a(n2) : o2 !== void 0 ? typeof i2 == "string" ? a(n2).fill(o2, i2) : a(n2).fill(o2) : a(n2); - var n2, o2, i2; - }, d.allocUnsafe = function(e3) { - return l(e3); - }, d.allocUnsafeSlow = function(e3) { - return l(e3); - }, d.isBuffer = function(e3) { - return e3 != null && e3._isBuffer === true && e3 !== d.prototype; - }, d.compare = function(e3, t2) { - if (R(e3, Uint8Array) && (e3 = d.from(e3, e3.offset, e3.byteLength)), R(t2, Uint8Array) && (t2 = d.from(t2, t2.offset, t2.byteLength)), !d.isBuffer(e3) || !d.isBuffer(t2)) - throw new TypeError('The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array'); - if (e3 === t2) - return 0; - for (var r2 = e3.length, n2 = t2.length, o2 = 0, i2 = Math.min(r2, n2); o2 < i2; ++o2) - if (e3[o2] !== t2[o2]) { - r2 = e3[o2], n2 = t2[o2]; - break; - } - return r2 < n2 ? -1 : n2 < r2 ? 1 : 0; - }, d.isEncoding = function(e3) { - switch (String(e3).toLowerCase()) { - case "hex": - case "utf8": - case "utf-8": - case "ascii": - case "latin1": - case "binary": - case "base64": - case "ucs2": - case "ucs-2": - case "utf16le": - case "utf-16le": - return true; - default: - return false; - } - }, d.concat = function(e3, t2) { - if (!Array.isArray(e3)) - throw new TypeError('"list" argument must be an Array of Buffers'); - if (e3.length === 0) - return d.alloc(0); - var r2; - if (t2 === void 0) - for (r2 = t2 = 0; r2 < e3.length; ++r2) - t2 += e3[r2].length; - var n2 = d.allocUnsafe(t2), o2 = 0; - for (r2 = 0; r2 < e3.length; ++r2) { - var i2 = e3[r2]; - if (R(i2, Uint8Array) && (i2 = d.from(i2)), !d.isBuffer(i2)) - throw new TypeError('"list" argument must be an Array of Buffers'); - i2.copy(n2, o2), o2 += i2.length; - } - return n2; - }, d.byteLength = f, d.prototype._isBuffer = true, d.prototype.swap16 = function() { - var e3 = this.length; - if (e3 % 2 != 0) - throw new RangeError("Buffer size must be a multiple of 16-bits"); - for (var t2 = 0; t2 < e3; t2 += 2) - h(this, t2, t2 + 1); - return this; - }, d.prototype.swap32 = function() { - var e3 = this.length; - if (e3 % 4 != 0) - throw new RangeError("Buffer size must be a multiple of 32-bits"); - for (var t2 = 0; t2 < e3; t2 += 4) - h(this, t2, t2 + 3), h(this, t2 + 1, t2 + 2); - return this; - }, d.prototype.swap64 = function() { - var e3 = this.length; - if (e3 % 8 != 0) - throw new RangeError("Buffer size must be a multiple of 64-bits"); - for (var t2 = 0; t2 < e3; t2 += 8) - h(this, t2, t2 + 7), h(this, t2 + 1, t2 + 6), h(this, t2 + 2, t2 + 5), h(this, t2 + 3, t2 + 4); - return this; - }, d.prototype.toLocaleString = d.prototype.toString = function() { - var e3 = this.length; - return e3 === 0 ? "" : arguments.length === 0 ? _(this, 0, e3) : function(e4, t2, r2) { - var n2 = false; - if ((t2 === void 0 || t2 < 0) && (t2 = 0), t2 > this.length) - return ""; - if ((r2 === void 0 || r2 > this.length) && (r2 = this.length), r2 <= 0) - return ""; - if ((r2 >>>= 0) <= (t2 >>>= 0)) - return ""; - for (e4 = e4 || "utf8"; ; ) - switch (e4) { - case "hex": - return j(this, t2, r2); - case "utf8": - case "utf-8": - return _(this, t2, r2); - case "ascii": - return w(this, t2, r2); - case "latin1": - case "binary": - return S(this, t2, r2); - case "base64": - return b(this, t2, r2); - case "ucs2": - case "ucs-2": - case "utf16le": - case "utf-16le": - return M(this, t2, r2); - default: - if (n2) - throw new TypeError("Unknown encoding: " + e4); - e4 = (e4 + "").toLowerCase(), n2 = true; - } - }.apply(this, arguments); - }, d.prototype.equals = function(e3) { - if (!d.isBuffer(e3)) - throw new TypeError("Argument must be a Buffer"); - return this === e3 || d.compare(this, e3) === 0; - }, d.prototype.inspect = function() { - var e3 = "", t2 = N.INSPECT_MAX_BYTES; - return e3 = this.toString("hex", 0, t2).replace(/(.{2})/g, "$1 ").trim(), this.length > t2 && (e3 += " ... "), ""; - }, e2 && (d.prototype[e2] = d.prototype.inspect), d.prototype.compare = function(e3, t2, r2, n2, o2) { - if (R(e3, Uint8Array) && (e3 = d.from(e3, e3.offset, e3.byteLength)), !d.isBuffer(e3)) - throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type ' + typeof e3); - if (t2 === void 0 && (t2 = 0), r2 === void 0 && (r2 = e3 ? e3.length : 0), n2 === void 0 && (n2 = 0), o2 === void 0 && (o2 = this.length), t2 < 0 || r2 > e3.length || n2 < 0 || o2 > this.length) - throw new RangeError("out of range index"); - if (o2 <= n2 && r2 <= t2) - return 0; - if (o2 <= n2) - return -1; - if (r2 <= t2) - return 1; - if (this === e3) - return 0; - for (var i2 = (o2 >>>= 0) - (n2 >>>= 0), a2 = (r2 >>>= 0) - (t2 >>>= 0), s2 = Math.min(i2, a2), l2 = this.slice(n2, o2), u2 = e3.slice(t2, r2), c2 = 0; c2 < s2; ++c2) - if (l2[c2] !== u2[c2]) { - i2 = l2[c2], a2 = u2[c2]; - break; - } - return i2 < a2 ? -1 : a2 < i2 ? 1 : 0; - }, d.prototype.includes = function(e3, t2, r2) { - return this.indexOf(e3, t2, r2) !== -1; - }, d.prototype.indexOf = function(e3, t2, r2) { - return p(this, e3, t2, r2, true); - }, d.prototype.lastIndexOf = function(e3, t2, r2) { - return p(this, e3, t2, r2, false); - }, d.prototype.write = function(e3, t2, r2, n2) { - if (t2 === void 0) - n2 = "utf8", r2 = this.length, t2 = 0; - else if (r2 === void 0 && typeof t2 == "string") - n2 = t2, r2 = this.length, t2 = 0; - else { - if (!isFinite(t2)) - throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported"); - t2 >>>= 0, isFinite(r2) ? (r2 >>>= 0, n2 === void 0 && (n2 = "utf8")) : (n2 = r2, r2 = void 0); - } - var o2 = this.length - t2; - if ((r2 === void 0 || o2 < r2) && (r2 = o2), 0 < e3.length && (r2 < 0 || t2 < 0) || t2 > this.length) - throw new RangeError("Attempt to write outside buffer bounds"); - n2 = n2 || "utf8"; - for (var i2, a2, s2, l2, u2, c2, d2 = false; ; ) - switch (n2) { - case "hex": - return m(this, e3, t2, r2); - case "utf8": - case "utf-8": - return u2 = t2, c2 = r2, A(P(e3, (l2 = this).length - u2), l2, u2, c2); - case "ascii": - return g(this, e3, t2, r2); - case "latin1": - case "binary": - return g(this, e3, t2, r2); - case "base64": - return i2 = this, a2 = t2, s2 = r2, A(k(e3), i2, a2, s2); - case "ucs2": - case "ucs-2": - case "utf16le": - case "utf-16le": - return v(this, e3, t2, r2); - default: - if (d2) - throw new TypeError("Unknown encoding: " + n2); - n2 = ("" + n2).toLowerCase(), d2 = true; - } - }, d.prototype.toJSON = function() { - return { type: "Buffer", data: Array.prototype.slice.call(this._arr || this, 0) }; - }; - var x = 4096; - function w(e3, t2, r2) { - var n2 = ""; - r2 = Math.min(e3.length, r2); - for (var o2 = t2; o2 < r2; ++o2) - n2 += String.fromCharCode(127 & e3[o2]); - return n2; - } - function S(e3, t2, r2) { - var n2 = ""; - r2 = Math.min(e3.length, r2); - for (var o2 = t2; o2 < r2; ++o2) - n2 += String.fromCharCode(e3[o2]); - return n2; - } - function j(e3, t2, r2) { - var n2 = e3.length; - (!t2 || t2 < 0) && (t2 = 0), (!r2 || r2 < 0 || n2 < r2) && (r2 = n2); - for (var o2 = "", i2 = t2; i2 < r2; ++i2) - o2 += I[e3[i2]]; - return o2; - } - function M(e3, t2, r2) { - for (var n2 = e3.slice(t2, r2), o2 = "", i2 = 0; i2 < n2.length; i2 += 2) - o2 += String.fromCharCode(n2[i2] + 256 * n2[i2 + 1]); - return o2; - } - function E(e3, t2, r2) { - if (e3 % 1 != 0 || e3 < 0) - throw new RangeError("offset is not uint"); - if (r2 < e3 + t2) - throw new RangeError("Trying to access beyond buffer length"); - } - function T(e3, t2, r2, n2, o2, i2) { - if (!d.isBuffer(e3)) - throw new TypeError('"buffer" argument must be a Buffer instance'); - if (o2 < t2 || t2 < i2) - throw new RangeError('"value" argument is out of bounds'); - if (r2 + n2 > e3.length) - throw new RangeError("Index out of range"); - } - function O(e3, t2, r2, n2) { - if (r2 + n2 > e3.length) - throw new RangeError("Index out of range"); - if (r2 < 0) - throw new RangeError("Index out of range"); - } - function C(e3, t2, r2, n2, o2) { - return t2 = +t2, r2 >>>= 0, o2 || O(e3, 0, r2, 4), i.write(e3, t2, r2, n2, 23, 4), r2 + 4; - } - function L(e3, t2, r2, n2, o2) { - return t2 = +t2, r2 >>>= 0, o2 || O(e3, 0, r2, 8), i.write(e3, t2, r2, n2, 52, 8), r2 + 8; - } - d.prototype.slice = function(e3, t2) { - var r2 = this.length; - (e3 = ~~e3) < 0 ? (e3 += r2) < 0 && (e3 = 0) : r2 < e3 && (e3 = r2), (t2 = t2 === void 0 ? r2 : ~~t2) < 0 ? (t2 += r2) < 0 && (t2 = 0) : r2 < t2 && (t2 = r2), t2 < e3 && (t2 = e3); - var n2 = this.subarray(e3, t2); - return Object.setPrototypeOf(n2, d.prototype), n2; - }, d.prototype.readUIntLE = function(e3, t2, r2) { - e3 >>>= 0, t2 >>>= 0, r2 || E(e3, t2, this.length); - for (var n2 = this[e3], o2 = 1, i2 = 0; ++i2 < t2 && (o2 *= 256); ) - n2 += this[e3 + i2] * o2; - return n2; - }, d.prototype.readUIntBE = function(e3, t2, r2) { - e3 >>>= 0, t2 >>>= 0, r2 || E(e3, t2, this.length); - for (var n2 = this[e3 + --t2], o2 = 1; 0 < t2 && (o2 *= 256); ) - n2 += this[e3 + --t2] * o2; - return n2; - }, d.prototype.readUInt8 = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 1, this.length), this[e3]; - }, d.prototype.readUInt16LE = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 2, this.length), this[e3] | this[e3 + 1] << 8; - }, d.prototype.readUInt16BE = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 2, this.length), this[e3] << 8 | this[e3 + 1]; - }, d.prototype.readUInt32LE = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 4, this.length), (this[e3] | this[e3 + 1] << 8 | this[e3 + 2] << 16) + 16777216 * this[e3 + 3]; - }, d.prototype.readUInt32BE = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 4, this.length), 16777216 * this[e3] + (this[e3 + 1] << 16 | this[e3 + 2] << 8 | this[e3 + 3]); - }, d.prototype.readIntLE = function(e3, t2, r2) { - e3 >>>= 0, t2 >>>= 0, r2 || E(e3, t2, this.length); - for (var n2 = this[e3], o2 = 1, i2 = 0; ++i2 < t2 && (o2 *= 256); ) - n2 += this[e3 + i2] * o2; - return (o2 *= 128) <= n2 && (n2 -= Math.pow(2, 8 * t2)), n2; - }, d.prototype.readIntBE = function(e3, t2, r2) { - e3 >>>= 0, t2 >>>= 0, r2 || E(e3, t2, this.length); - for (var n2 = t2, o2 = 1, i2 = this[e3 + --n2]; 0 < n2 && (o2 *= 256); ) - i2 += this[e3 + --n2] * o2; - return (o2 *= 128) <= i2 && (i2 -= Math.pow(2, 8 * t2)), i2; - }, d.prototype.readInt8 = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 1, this.length), 128 & this[e3] ? -1 * (255 - this[e3] + 1) : this[e3]; - }, d.prototype.readInt16LE = function(e3, t2) { - e3 >>>= 0, t2 || E(e3, 2, this.length); - var r2 = this[e3] | this[e3 + 1] << 8; - return 32768 & r2 ? 4294901760 | r2 : r2; - }, d.prototype.readInt16BE = function(e3, t2) { - e3 >>>= 0, t2 || E(e3, 2, this.length); - var r2 = this[e3 + 1] | this[e3] << 8; - return 32768 & r2 ? 4294901760 | r2 : r2; - }, d.prototype.readInt32LE = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 4, this.length), this[e3] | this[e3 + 1] << 8 | this[e3 + 2] << 16 | this[e3 + 3] << 24; - }, d.prototype.readInt32BE = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 4, this.length), this[e3] << 24 | this[e3 + 1] << 16 | this[e3 + 2] << 8 | this[e3 + 3]; - }, d.prototype.readFloatLE = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 4, this.length), i.read(this, e3, true, 23, 4); - }, d.prototype.readFloatBE = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 4, this.length), i.read(this, e3, false, 23, 4); - }, d.prototype.readDoubleLE = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 8, this.length), i.read(this, e3, true, 52, 8); - }, d.prototype.readDoubleBE = function(e3, t2) { - return e3 >>>= 0, t2 || E(e3, 8, this.length), i.read(this, e3, false, 52, 8); - }, d.prototype.writeUIntLE = function(e3, t2, r2, n2) { - e3 = +e3, t2 >>>= 0, r2 >>>= 0, n2 || T(this, e3, t2, r2, Math.pow(2, 8 * r2) - 1, 0); - var o2 = 1, i2 = 0; - for (this[t2] = 255 & e3; ++i2 < r2 && (o2 *= 256); ) - this[t2 + i2] = e3 / o2 & 255; - return t2 + r2; - }, d.prototype.writeUIntBE = function(e3, t2, r2, n2) { - e3 = +e3, t2 >>>= 0, r2 >>>= 0, n2 || T(this, e3, t2, r2, Math.pow(2, 8 * r2) - 1, 0); - var o2 = r2 - 1, i2 = 1; - for (this[t2 + o2] = 255 & e3; 0 <= --o2 && (i2 *= 256); ) - this[t2 + o2] = e3 / i2 & 255; - return t2 + r2; - }, d.prototype.writeUInt8 = function(e3, t2, r2) { - return e3 = +e3, t2 >>>= 0, r2 || T(this, e3, t2, 1, 255, 0), this[t2] = 255 & e3, t2 + 1; - }, d.prototype.writeUInt16LE = function(e3, t2, r2) { - return e3 = +e3, t2 >>>= 0, r2 || T(this, e3, t2, 2, 65535, 0), this[t2] = 255 & e3, this[t2 + 1] = e3 >>> 8, t2 + 2; - }, d.prototype.writeUInt16BE = function(e3, t2, r2) { - return e3 = +e3, t2 >>>= 0, r2 || T(this, e3, t2, 2, 65535, 0), this[t2] = e3 >>> 8, this[t2 + 1] = 255 & e3, t2 + 2; - }, d.prototype.writeUInt32LE = function(e3, t2, r2) { - return e3 = +e3, t2 >>>= 0, r2 || T(this, e3, t2, 4, 4294967295, 0), this[t2 + 3] = e3 >>> 24, this[t2 + 2] = e3 >>> 16, this[t2 + 1] = e3 >>> 8, this[t2] = 255 & e3, t2 + 4; - }, d.prototype.writeUInt32BE = function(e3, t2, r2) { - return e3 = +e3, t2 >>>= 0, r2 || T(this, e3, t2, 4, 4294967295, 0), this[t2] = e3 >>> 24, this[t2 + 1] = e3 >>> 16, this[t2 + 2] = e3 >>> 8, this[t2 + 3] = 255 & e3, t2 + 4; - }, d.prototype.writeIntLE = function(e3, t2, r2, n2) { - if (e3 = +e3, t2 >>>= 0, !n2) { - var o2 = Math.pow(2, 8 * r2 - 1); - T(this, e3, t2, r2, o2 - 1, -o2); - } - var i2 = 0, a2 = 1, s2 = 0; - for (this[t2] = 255 & e3; ++i2 < r2 && (a2 *= 256); ) - e3 < 0 && s2 === 0 && this[t2 + i2 - 1] !== 0 && (s2 = 1), this[t2 + i2] = (e3 / a2 >> 0) - s2 & 255; - return t2 + r2; - }, d.prototype.writeIntBE = function(e3, t2, r2, n2) { - if (e3 = +e3, t2 >>>= 0, !n2) { - var o2 = Math.pow(2, 8 * r2 - 1); - T(this, e3, t2, r2, o2 - 1, -o2); - } - var i2 = r2 - 1, a2 = 1, s2 = 0; - for (this[t2 + i2] = 255 & e3; 0 <= --i2 && (a2 *= 256); ) - e3 < 0 && s2 === 0 && this[t2 + i2 + 1] !== 0 && (s2 = 1), this[t2 + i2] = (e3 / a2 >> 0) - s2 & 255; - return t2 + r2; - }, d.prototype.writeInt8 = function(e3, t2, r2) { - return e3 = +e3, t2 >>>= 0, r2 || T(this, e3, t2, 1, 127, -128), e3 < 0 && (e3 = 255 + e3 + 1), this[t2] = 255 & e3, t2 + 1; - }, d.prototype.writeInt16LE = function(e3, t2, r2) { - return e3 = +e3, t2 >>>= 0, r2 || T(this, e3, t2, 2, 32767, -32768), this[t2] = 255 & e3, this[t2 + 1] = e3 >>> 8, t2 + 2; - }, d.prototype.writeInt16BE = function(e3, t2, r2) { - return e3 = +e3, t2 >>>= 0, r2 || T(this, e3, t2, 2, 32767, -32768), this[t2] = e3 >>> 8, this[t2 + 1] = 255 & e3, t2 + 2; - }, d.prototype.writeInt32LE = function(e3, t2, r2) { - return e3 = +e3, t2 >>>= 0, r2 || T(this, e3, t2, 4, 2147483647, -2147483648), this[t2] = 255 & e3, this[t2 + 1] = e3 >>> 8, this[t2 + 2] = e3 >>> 16, this[t2 + 3] = e3 >>> 24, t2 + 4; - }, d.prototype.writeInt32BE = function(e3, t2, r2) { - return e3 = +e3, t2 >>>= 0, r2 || T(this, e3, t2, 4, 2147483647, -2147483648), e3 < 0 && (e3 = 4294967295 + e3 + 1), this[t2] = e3 >>> 24, this[t2 + 1] = e3 >>> 16, this[t2 + 2] = e3 >>> 8, this[t2 + 3] = 255 & e3, t2 + 4; - }, d.prototype.writeFloatLE = function(e3, t2, r2) { - return C(this, e3, t2, true, r2); - }, d.prototype.writeFloatBE = function(e3, t2, r2) { - return C(this, e3, t2, false, r2); - }, d.prototype.writeDoubleLE = function(e3, t2, r2) { - return L(this, e3, t2, true, r2); - }, d.prototype.writeDoubleBE = function(e3, t2, r2) { - return L(this, e3, t2, false, r2); - }, d.prototype.copy = function(e3, t2, r2, n2) { - if (!d.isBuffer(e3)) - throw new TypeError("argument should be a Buffer"); - if (r2 = r2 || 0, n2 || n2 === 0 || (n2 = this.length), t2 >= e3.length && (t2 = e3.length), t2 = t2 || 0, 0 < n2 && n2 < r2 && (n2 = r2), n2 === r2) - return 0; - if (e3.length === 0 || this.length === 0) - return 0; - if (t2 < 0) - throw new RangeError("targetStart out of bounds"); - if (r2 < 0 || r2 >= this.length) - throw new RangeError("Index out of range"); - if (n2 < 0) - throw new RangeError("sourceEnd out of bounds"); - n2 > this.length && (n2 = this.length), e3.length - t2 < n2 - r2 && (n2 = e3.length - t2 + r2); - var o2 = n2 - r2; - if (this === e3 && typeof Uint8Array.prototype.copyWithin == "function") - this.copyWithin(t2, r2, n2); - else if (this === e3 && r2 < t2 && t2 < n2) - for (var i2 = o2 - 1; 0 <= i2; --i2) - e3[i2 + t2] = this[i2 + r2]; - else - Uint8Array.prototype.set.call(e3, this.subarray(r2, n2), t2); - return o2; - }, d.prototype.fill = function(e3, t2, r2, n2) { - if (typeof e3 == "string") { - if (typeof t2 == "string" ? (n2 = t2, t2 = 0, r2 = this.length) : typeof r2 == "string" && (n2 = r2, r2 = this.length), n2 !== void 0 && typeof n2 != "string") - throw new TypeError("encoding must be a string"); - if (typeof n2 == "string" && !d.isEncoding(n2)) - throw new TypeError("Unknown encoding: " + n2); - if (e3.length === 1) { - var o2 = e3.charCodeAt(0); - (n2 === "utf8" && o2 < 128 || n2 === "latin1") && (e3 = o2); - } - } else - typeof e3 == "number" ? e3 &= 255 : typeof e3 == "boolean" && (e3 = Number(e3)); - if (t2 < 0 || this.length < t2 || this.length < r2) - throw new RangeError("Out of range index"); - if (r2 <= t2) - return this; - var i2; - if (t2 >>>= 0, r2 = r2 === void 0 ? this.length : r2 >>> 0, typeof (e3 = e3 || 0) == "number") - for (i2 = t2; i2 < r2; ++i2) - this[i2] = e3; - else { - var a2 = d.isBuffer(e3) ? e3 : d.from(e3, n2), s2 = a2.length; - if (s2 === 0) - throw new TypeError('The value "' + e3 + '" is invalid for argument "value"'); - for (i2 = 0; i2 < r2 - t2; ++i2) - this[i2 + t2] = a2[i2 % s2]; - } - return this; - }; - var t = /[^+/0-9A-Za-z-_]/g; - function P(e3, t2) { - var r2; - t2 = t2 || 1 / 0; - for (var n2 = e3.length, o2 = null, i2 = [], a2 = 0; a2 < n2; ++a2) { - if (55295 < (r2 = e3.charCodeAt(a2)) && r2 < 57344) { - if (!o2) { - if (56319 < r2) { - -1 < (t2 -= 3) && i2.push(239, 191, 189); - continue; - } - if (a2 + 1 === n2) { - -1 < (t2 -= 3) && i2.push(239, 191, 189); - continue; - } - o2 = r2; - continue; - } - if (r2 < 56320) { - -1 < (t2 -= 3) && i2.push(239, 191, 189), o2 = r2; - continue; - } - r2 = 65536 + (o2 - 55296 << 10 | r2 - 56320); - } else - o2 && -1 < (t2 -= 3) && i2.push(239, 191, 189); - if (o2 = null, r2 < 128) { - if (--t2 < 0) - break; - i2.push(r2); - } else if (r2 < 2048) { - if ((t2 -= 2) < 0) - break; - i2.push(r2 >> 6 | 192, 63 & r2 | 128); - } else if (r2 < 65536) { - if ((t2 -= 3) < 0) - break; - i2.push(r2 >> 12 | 224, r2 >> 6 & 63 | 128, 63 & r2 | 128); - } else { - if (!(r2 < 1114112)) - throw new Error("Invalid code point"); - if ((t2 -= 4) < 0) - break; - i2.push(r2 >> 18 | 240, r2 >> 12 & 63 | 128, r2 >> 6 & 63 | 128, 63 & r2 | 128); - } - } - return i2; - } - function k(e3) { - return n.toByteArray(function(e4) { - if ((e4 = (e4 = e4.split("=")[0]).trim().replace(t, "")).length < 2) - return ""; - for (; e4.length % 4 != 0; ) - e4 += "="; - return e4; - }(e3)); - } - function A(e3, t2, r2, n2) { - for (var o2 = 0; o2 < n2 && !(o2 + r2 >= t2.length || o2 >= e3.length); ++o2) - t2[o2 + r2] = e3[o2]; - return o2; - } - function R(e3, t2) { - return e3 instanceof t2 || e3 != null && e3.constructor != null && e3.constructor.name != null && e3.constructor.name === t2.name; - } - function D(e3) { - return e3 != e3; - } - var I = function() { - for (var e3 = "0123456789abcdef", t2 = new Array(256), r2 = 0; r2 < 16; ++r2) - for (var n2 = 16 * r2, o2 = 0; o2 < 16; ++o2) - t2[n2 + o2] = e3[r2] + e3[o2]; - return t2; - }(); - }).call(this, U("buffer").Buffer); - }, { "base64-js": 1, buffer: 4, ieee754: 233 }], 5: [function(e, t, r) { - t.exports = function(e2) { - if (typeof e2 != "function") - throw TypeError(String(e2) + " is not a function"); - return e2; - }; - }, {}], 6: [function(e, t, r) { - var n = e("../internals/is-object"); - t.exports = function(e2) { - if (!n(e2) && e2 !== null) - throw TypeError("Can't set " + String(e2) + " as a prototype"); - return e2; - }; - }, { "../internals/is-object": 73 }], 7: [function(e, t, r) { - var n = e("../internals/well-known-symbol"), o = e("../internals/object-create"), i = e("../internals/object-define-property"), a = n("unscopables"), s = Array.prototype; - s[a] == null && i.f(s, a, { configurable: true, value: o(null) }), t.exports = function(e2) { - s[a][e2] = true; - }; - }, { "../internals/object-create": 89, "../internals/object-define-property": 91, "../internals/well-known-symbol": 145 }], 8: [function(e, t, r) { - "use strict"; - var n = e("../internals/string-multibyte").charAt; - t.exports = function(e2, t2, r2) { - return t2 + (r2 ? n(e2, t2).length : 1); - }; - }, { "../internals/string-multibyte": 122 }], 9: [function(e, t, r) { - t.exports = function(e2, t2, r2) { - if (!(e2 instanceof t2)) - throw TypeError("Incorrect " + (r2 ? r2 + " " : "") + "invocation"); - return e2; - }; - }, {}], 10: [function(e, t, r) { - var n = e("../internals/is-object"); - t.exports = function(e2) { - if (!n(e2)) - throw TypeError(String(e2) + " is not an object"); - return e2; - }; - }, { "../internals/is-object": 73 }], 11: [function(e, t, r) { - t.exports = typeof ArrayBuffer != "undefined" && typeof DataView != "undefined"; - }, {}], 12: [function(e, t, r) { - "use strict"; - function n(e2) { - return l(e2) && u(L, c(e2)); - } - var o, i = e("../internals/array-buffer-native"), a = e("../internals/descriptors"), s = e("../internals/global"), l = e("../internals/is-object"), u = e("../internals/has"), c = e("../internals/classof"), d = e("../internals/create-non-enumerable-property"), f = e("../internals/redefine"), h = e("../internals/object-define-property").f, p = e("../internals/object-get-prototype-of"), y = e("../internals/object-set-prototype-of"), m = e("../internals/well-known-symbol"), g = e("../internals/uid"), v = s.Int8Array, b = v && v.prototype, _ = s.Uint8ClampedArray, x = _ && _.prototype, w = v && p(v), S = b && p(b), j = Object.prototype, M = j.isPrototypeOf, E = m("toStringTag"), T = g("TYPED_ARRAY_TAG"), O = i && !!y && c(s.opera) !== "Opera", C = false, L = { Int8Array: 1, Uint8Array: 1, Uint8ClampedArray: 1, Int16Array: 2, Uint16Array: 2, Int32Array: 4, Uint32Array: 4, Float32Array: 4, Float64Array: 8 }; - for (o in L) - s[o] || (O = false); - if ((!O || typeof w != "function" || w === Function.prototype) && (w = function() { - throw TypeError("Incorrect invocation"); - }, O)) - for (o in L) - s[o] && y(s[o], w); - if ((!O || !S || S === j) && (S = w.prototype, O)) - for (o in L) - s[o] && y(s[o].prototype, S); - if (O && p(x) !== S && y(x, S), a && !u(S, E)) - for (o in C = true, h(S, E, { get: function() { - return l(this) ? this[T] : void 0; - } }), L) - s[o] && d(s[o], T, o); - t.exports = { NATIVE_ARRAY_BUFFER_VIEWS: O, TYPED_ARRAY_TAG: C && T, aTypedArray: function(e2) { - if (n(e2)) - return e2; - throw TypeError("Target is not a typed array"); - }, aTypedArrayConstructor: function(e2) { - if (y) { - if (M.call(w, e2)) - return e2; - } else - for (var t2 in L) - if (u(L, o)) { - var r2 = s[t2]; - if (r2 && (e2 === r2 || M.call(r2, e2))) - return e2; - } - throw TypeError("Target is not a typed array constructor"); - }, exportTypedArrayMethod: function(e2, t2, r2) { - if (a) { - if (r2) - for (var n2 in L) { - var o2 = s[n2]; - o2 && u(o2.prototype, e2) && delete o2.prototype[e2]; - } - S[e2] && !r2 || f(S, e2, r2 ? t2 : O && b[e2] || t2); - } - }, exportTypedArrayStaticMethod: function(e2, t2, r2) { - var n2, o2; - if (a) { - if (y) { - if (r2) - for (n2 in L) - (o2 = s[n2]) && u(o2, e2) && delete o2[e2]; - if (w[e2] && !r2) - return; - try { - return f(w, e2, r2 ? t2 : O && v[e2] || t2); - } catch (e3) { - } - } - for (n2 in L) - !(o2 = s[n2]) || o2[e2] && !r2 || f(o2, e2, t2); - } - }, isView: function(e2) { - var t2 = c(e2); - return t2 === "DataView" || u(L, t2); - }, isTypedArray: n, TypedArray: w, TypedArrayPrototype: S }; - }, { "../internals/array-buffer-native": 11, "../internals/classof": 29, "../internals/create-non-enumerable-property": 37, "../internals/descriptors": 42, "../internals/global": 58, "../internals/has": 59, "../internals/is-object": 73, "../internals/object-define-property": 91, "../internals/object-get-prototype-of": 96, "../internals/object-set-prototype-of": 100, "../internals/redefine": 107, "../internals/uid": 142, "../internals/well-known-symbol": 145 }], 13: [function(e, t, r) { - "use strict"; - function n(e2) { - return [255 & e2]; - } - function o(e2) { - return [255 & e2, e2 >> 8 & 255]; - } - function i(e2) { - return [255 & e2, e2 >> 8 & 255, e2 >> 16 & 255, e2 >> 24 & 255]; - } - function a(e2) { - return e2[3] << 24 | e2[2] << 16 | e2[1] << 8 | e2[0]; - } - function s(e2) { - return V(e2, 23, 4); - } - function l(e2) { - return V(e2, 52, 8); - } - function u(e2, t2) { - E(e2[R], t2, { get: function() { - return L(this)[t2]; - } }); - } - function c(e2, t2, r2, n2) { - var o2 = x(r2), i2 = L(e2); - if (o2 + t2 > i2.byteLength) - throw G(D); - var a2 = L(i2.buffer).bytes, s2 = o2 + i2.byteOffset, l2 = a2.slice(s2, s2 + t2); - return n2 ? l2 : l2.reverse(); - } - function d(e2, t2, r2, n2, o2, i2) { - var a2 = x(r2), s2 = L(e2); - if (a2 + t2 > s2.byteLength) - throw G(D); - for (var l2 = L(s2.buffer).bytes, u2 = a2 + s2.byteOffset, c2 = n2(+o2), d2 = 0; d2 < t2; d2++) - l2[u2 + d2] = c2[i2 ? d2 : t2 - d2 - 1]; - } - var f = e("../internals/global"), h = e("../internals/descriptors"), p = e("../internals/array-buffer-native"), y = e("../internals/create-non-enumerable-property"), m = e("../internals/redefine-all"), g = e("../internals/fails"), v = e("../internals/an-instance"), b = e("../internals/to-integer"), _ = e("../internals/to-length"), x = e("../internals/to-index"), w = e("../internals/ieee754"), S = e("../internals/object-get-prototype-of"), j = e("../internals/object-set-prototype-of"), M = e("../internals/object-get-own-property-names").f, E = e("../internals/object-define-property").f, T = e("../internals/array-fill"), O = e("../internals/set-to-string-tag"), C = e("../internals/internal-state"), L = C.get, P = C.set, k = "ArrayBuffer", A = "DataView", R = "prototype", D = "Wrong index", I = f[k], U = I, N = f[A], F = N && N[R], B = Object.prototype, G = f.RangeError, V = w.pack, z = w.unpack; - if (p) { - if (!g(function() { - I(1); - }) || !g(function() { - new I(-1); - }) || g(function() { - return new I(), new I(1.5), new I(NaN), I.name != k; - })) { - for (var H, W = (U = function(e2) { - return v(this, U), new I(x(e2)); - })[R] = I[R], q = M(I), X = 0; q.length > X; ) - (H = q[X++]) in U || y(U, H, I[H]); - W.constructor = U; - } - j && S(F) !== B && j(F, B); - var Y = new N(new U(2)), Z = F.setInt8; - Y.setInt8(0, 2147483648), Y.setInt8(1, 2147483649), !Y.getInt8(0) && Y.getInt8(1) || m(F, { setInt8: function(e2, t2) { - Z.call(this, e2, t2 << 24 >> 24); - }, setUint8: function(e2, t2) { - Z.call(this, e2, t2 << 24 >> 24); - } }, { unsafe: true }); - } else - U = function(e2) { - v(this, U, k); - var t2 = x(e2); - P(this, { bytes: T.call(new Array(t2), 0), byteLength: t2 }), h || (this.byteLength = t2); - }, N = function(e2, t2, r2) { - v(this, N, A), v(e2, U, A); - var n2 = L(e2).byteLength, o2 = b(t2); - if (o2 < 0 || n2 < o2) - throw G("Wrong offset"); - if (n2 < o2 + (r2 = r2 === void 0 ? n2 - o2 : _(r2))) - throw G("Wrong length"); - P(this, { buffer: e2, byteLength: r2, byteOffset: o2 }), h || (this.buffer = e2, this.byteLength = r2, this.byteOffset = o2); - }, h && (u(U, "byteLength"), u(N, "buffer"), u(N, "byteLength"), u(N, "byteOffset")), m(N[R], { getInt8: function(e2) { - return c(this, 1, e2)[0] << 24 >> 24; - }, getUint8: function(e2) { - return c(this, 1, e2)[0]; - }, getInt16: function(e2, t2) { - var r2 = c(this, 2, e2, 1 < arguments.length ? t2 : void 0); - return (r2[1] << 8 | r2[0]) << 16 >> 16; - }, getUint16: function(e2, t2) { - var r2 = c(this, 2, e2, 1 < arguments.length ? t2 : void 0); - return r2[1] << 8 | r2[0]; - }, getInt32: function(e2, t2) { - return a(c(this, 4, e2, 1 < arguments.length ? t2 : void 0)); - }, getUint32: function(e2, t2) { - return a(c(this, 4, e2, 1 < arguments.length ? t2 : void 0)) >>> 0; - }, getFloat32: function(e2, t2) { - return z(c(this, 4, e2, 1 < arguments.length ? t2 : void 0), 23); - }, getFloat64: function(e2, t2) { - return z(c(this, 8, e2, 1 < arguments.length ? t2 : void 0), 52); - }, setInt8: function(e2, t2) { - d(this, 1, e2, n, t2); - }, setUint8: function(e2, t2) { - d(this, 1, e2, n, t2); - }, setInt16: function(e2, t2, r2) { - d(this, 2, e2, o, t2, 2 < arguments.length ? r2 : void 0); - }, setUint16: function(e2, t2, r2) { - d(this, 2, e2, o, t2, 2 < arguments.length ? r2 : void 0); - }, setInt32: function(e2, t2, r2) { - d(this, 4, e2, i, t2, 2 < arguments.length ? r2 : void 0); - }, setUint32: function(e2, t2, r2) { - d(this, 4, e2, i, t2, 2 < arguments.length ? r2 : void 0); - }, setFloat32: function(e2, t2, r2) { - d(this, 4, e2, s, t2, 2 < arguments.length ? r2 : void 0); - }, setFloat64: function(e2, t2, r2) { - d(this, 8, e2, l, t2, 2 < arguments.length ? r2 : void 0); - } }); - O(U, k), O(N, A), t.exports = { ArrayBuffer: U, DataView: N }; - }, { "../internals/an-instance": 9, "../internals/array-buffer-native": 11, "../internals/array-fill": 15, "../internals/create-non-enumerable-property": 37, "../internals/descriptors": 42, "../internals/fails": 50, "../internals/global": 58, "../internals/ieee754": 64, "../internals/internal-state": 69, "../internals/object-define-property": 91, "../internals/object-get-own-property-names": 94, "../internals/object-get-prototype-of": 96, "../internals/object-set-prototype-of": 100, "../internals/redefine-all": 106, "../internals/set-to-string-tag": 116, "../internals/to-index": 130, "../internals/to-integer": 132, "../internals/to-length": 133 }], 14: [function(e, t, r) { - "use strict"; - var c = e("../internals/to-object"), d = e("../internals/to-absolute-index"), f = e("../internals/to-length"), h = Math.min; - t.exports = [].copyWithin || function(e2, t2, r2) { - var n = c(this), o = f(n.length), i = d(e2, o), a = d(t2, o), s = 2 < arguments.length ? r2 : void 0, l = h((s === void 0 ? o : d(s, o)) - a, o - i), u = 1; - for (a < i && i < a + l && (u = -1, a += l - 1, i += l - 1); 0 < l--; ) - a in n ? n[i] = n[a] : delete n[i], i += u, a += u; - return n; - }; - }, { "../internals/to-absolute-index": 129, "../internals/to-length": 133, "../internals/to-object": 134 }], 15: [function(e, t, r) { - "use strict"; - var u = e("../internals/to-object"), c = e("../internals/to-absolute-index"), d = e("../internals/to-length"); - t.exports = function(e2, t2, r2) { - for (var n = u(this), o = d(n.length), i = arguments.length, a = c(1 < i ? t2 : void 0, o), s = 2 < i ? r2 : void 0, l = s === void 0 ? o : c(s, o); a < l; ) - n[a++] = e2; - return n; - }; - }, { "../internals/to-absolute-index": 129, "../internals/to-length": 133, "../internals/to-object": 134 }], 16: [function(e, t, r) { - "use strict"; - var n = e("../internals/array-iteration").forEach, o = e("../internals/array-method-is-strict"), i = e("../internals/array-method-uses-to-length"), a = o("forEach"), s = i("forEach"); - t.exports = a && s ? [].forEach : function(e2, t2) { - return n(this, e2, 1 < arguments.length ? t2 : void 0); - }; - }, { "../internals/array-iteration": 19, "../internals/array-method-is-strict": 22, "../internals/array-method-uses-to-length": 23 }], 17: [function(e, t, r) { - "use strict"; - var m = e("../internals/function-bind-context"), g = e("../internals/to-object"), v = e("../internals/call-with-safe-iteration-closing"), b = e("../internals/is-array-iterator-method"), _ = e("../internals/to-length"), x = e("../internals/create-property"), w = e("../internals/get-iterator-method"); - t.exports = function(e2, t2, r2) { - var n, o, i, a, s, l, u = g(e2), c = typeof this == "function" ? this : Array, d = arguments.length, f = 1 < d ? t2 : void 0, h = f !== void 0, p = w(u), y = 0; - if (h && (f = m(f, 2 < d ? r2 : void 0, 2)), p == null || c == Array && b(p)) - for (o = new c(n = _(u.length)); y < n; y++) - l = h ? f(u[y], y) : u[y], x(o, y, l); - else - for (s = (a = p.call(u)).next, o = new c(); !(i = s.call(a)).done; y++) - l = h ? v(a, f, [i.value, y], true) : i.value, x(o, y, l); - return o.length = y, o; - }; - }, { "../internals/call-with-safe-iteration-closing": 26, "../internals/create-property": 39, "../internals/function-bind-context": 53, "../internals/get-iterator-method": 56, "../internals/is-array-iterator-method": 70, "../internals/to-length": 133, "../internals/to-object": 134 }], 18: [function(e, t, r) { - function n(s) { - return function(e2, t2, r2) { - var n2, o = l(e2), i = u(o.length), a = c(r2, i); - if (s && t2 != t2) { - for (; a < i; ) - if ((n2 = o[a++]) != n2) - return true; - } else - for (; a < i; a++) - if ((s || a in o) && o[a] === t2) - return s || a || 0; - return !s && -1; - }; - } - var l = e("../internals/to-indexed-object"), u = e("../internals/to-length"), c = e("../internals/to-absolute-index"); - t.exports = { includes: n(true), indexOf: n(false) }; - }, { "../internals/to-absolute-index": 129, "../internals/to-indexed-object": 131, "../internals/to-length": 133 }], 19: [function(e, t, r) { - function n(h) { - var p = h == 1, y = h == 2, m = h == 3, g = h == 4, v = h == 6, b = h == 5 || v; - return function(e2, t2, r2, n2) { - for (var o, i, a = w(e2), s = x(a), l = _(t2, r2, 3), u = S(s.length), c = 0, d = n2 || j, f = p ? d(e2, u) : y ? d(e2, 0) : void 0; c < u; c++) - if ((b || c in s) && (i = l(o = s[c], c, a), h)) { - if (p) - f[c] = i; - else if (i) - switch (h) { - case 3: - return true; - case 5: - return o; - case 6: - return c; - case 2: - M.call(f, o); - } - else if (g) - return false; - } - return v ? -1 : m || g ? g : f; - }; - } - var _ = e("../internals/function-bind-context"), x = e("../internals/indexed-object"), w = e("../internals/to-object"), S = e("../internals/to-length"), j = e("../internals/array-species-create"), M = [].push; - t.exports = { forEach: n(0), map: n(1), filter: n(2), some: n(3), every: n(4), find: n(5), findIndex: n(6) }; - }, { "../internals/array-species-create": 25, "../internals/function-bind-context": 53, "../internals/indexed-object": 65, "../internals/to-length": 133, "../internals/to-object": 134 }], 20: [function(e, t, r) { - "use strict"; - var i = e("../internals/to-indexed-object"), a = e("../internals/to-integer"), s = e("../internals/to-length"), n = e("../internals/array-method-is-strict"), o = e("../internals/array-method-uses-to-length"), l = Math.min, u = [].lastIndexOf, c = !!u && 1 / [1].lastIndexOf(1, -0) < 0, d = n("lastIndexOf"), f = o("indexOf", { ACCESSORS: true, 1: 0 }), h = c || !d || !f; - t.exports = h ? function(e2, t2) { - if (c) - return u.apply(this, arguments) || 0; - var r2 = i(this), n2 = s(r2.length), o2 = n2 - 1; - for (1 < arguments.length && (o2 = l(o2, a(t2))), o2 < 0 && (o2 = n2 + o2); 0 <= o2; o2--) - if (o2 in r2 && r2[o2] === e2) - return o2 || 0; - return -1; - } : u; - }, { "../internals/array-method-is-strict": 22, "../internals/array-method-uses-to-length": 23, "../internals/to-indexed-object": 131, "../internals/to-integer": 132, "../internals/to-length": 133 }], 21: [function(e, t, r) { - var n = e("../internals/fails"), o = e("../internals/well-known-symbol"), i = e("../internals/engine-v8-version"), a = o("species"); - t.exports = function(t2) { - return 51 <= i || !n(function() { - var e2 = []; - return (e2.constructor = {})[a] = function() { - return { foo: 1 }; - }, e2[t2](Boolean).foo !== 1; - }); - }; - }, { "../internals/engine-v8-version": 47, "../internals/fails": 50, "../internals/well-known-symbol": 145 }], 22: [function(e, t, r) { - "use strict"; - var n = e("../internals/fails"); - t.exports = function(e2, t2) { - var r2 = [][e2]; - return !!r2 && n(function() { - r2.call(null, t2 || function() { - throw 1; - }, 1); - }); - }; - }, { "../internals/fails": 50 }], 23: [function(e, t, r) { - function a(e2) { - throw e2; - } - var s = e("../internals/descriptors"), l = e("../internals/fails"), u = e("../internals/has"), c = Object.defineProperty, d = {}; - t.exports = function(e2, t2) { - if (u(d, e2)) - return d[e2]; - var r2 = [][e2], n = !!u(t2 = t2 || {}, "ACCESSORS") && t2.ACCESSORS, o = u(t2, 0) ? t2[0] : a, i = u(t2, 1) ? t2[1] : void 0; - return d[e2] = !!r2 && !l(function() { - if (n && !s) - return true; - var e3 = { length: -1 }; - n ? c(e3, 1, { enumerable: true, get: a }) : e3[1] = 1, r2.call(e3, o, i); - }); - }; - }, { "../internals/descriptors": 42, "../internals/fails": 50, "../internals/has": 59 }], 24: [function(e, t, r) { - function n(u) { - return function(e2, t2, r2, n2) { - c(t2); - var o = d(e2), i = f(o), a = h(o.length), s = u ? a - 1 : 0, l = u ? -1 : 1; - if (r2 < 2) - for (; ; ) { - if (s in i) { - n2 = i[s], s += l; - break; - } - if (s += l, u ? s < 0 : a <= s) - throw TypeError("Reduce of empty array with no initial value"); - } - for (; u ? 0 <= s : s < a; s += l) - s in i && (n2 = t2(n2, i[s], s, o)); - return n2; - }; - } - var c = e("../internals/a-function"), d = e("../internals/to-object"), f = e("../internals/indexed-object"), h = e("../internals/to-length"); - t.exports = { left: n(false), right: n(true) }; - }, { "../internals/a-function": 5, "../internals/indexed-object": 65, "../internals/to-length": 133, "../internals/to-object": 134 }], 25: [function(e, t, r) { - var n = e("../internals/is-object"), o = e("../internals/is-array"), i = e("../internals/well-known-symbol")("species"); - t.exports = function(e2, t2) { - var r2; - return o(e2) && (typeof (r2 = e2.constructor) != "function" || r2 !== Array && !o(r2.prototype) ? n(r2) && (r2 = r2[i]) === null && (r2 = void 0) : r2 = void 0), new (r2 === void 0 ? Array : r2)(t2 === 0 ? 0 : t2); - }; - }, { "../internals/is-array": 71, "../internals/is-object": 73, "../internals/well-known-symbol": 145 }], 26: [function(e, t, r) { - var i = e("../internals/an-object"); - t.exports = function(t2, e2, r2, n) { - try { - return n ? e2(i(r2)[0], r2[1]) : e2(r2); - } catch (e3) { - var o = t2.return; - throw o !== void 0 && i(o.call(t2)), e3; - } - }; - }, { "../internals/an-object": 10 }], 27: [function(e, t, r) { - var o = e("../internals/well-known-symbol")("iterator"), i = false; - try { - var n = 0, a = { next: function() { - return { done: !!n++ }; - }, return: function() { - i = true; - } }; - a[o] = function() { - return this; - }, Array.from(a, function() { - throw 2; - }); - } catch (e2) { - } - t.exports = function(e2, t2) { - if (!t2 && !i) - return false; - var r2 = false; - try { - var n2 = {}; - n2[o] = function() { - return { next: function() { - return { done: r2 = true }; - } }; - }, e2(n2); - } catch (e3) { - } - return r2; - }; - }, { "../internals/well-known-symbol": 145 }], 28: [function(e, t, r) { - var n = {}.toString; - t.exports = function(e2) { - return n.call(e2).slice(8, -1); - }; - }, {}], 29: [function(e, t, r) { - var n = e("../internals/to-string-tag-support"), o = e("../internals/classof-raw"), i = e("../internals/well-known-symbol")("toStringTag"), a = o(function() { - return arguments; - }()) == "Arguments"; - t.exports = n ? o : function(e2) { - var t2, r2, n2; - return e2 === void 0 ? "Undefined" : e2 === null ? "Null" : typeof (r2 = function(e3, t3) { - try { - return e3[t3]; - } catch (e4) { - } - }(t2 = Object(e2), i)) == "string" ? r2 : a ? o(t2) : (n2 = o(t2)) == "Object" && typeof t2.callee == "function" ? "Arguments" : n2; - }; - }, { "../internals/classof-raw": 28, "../internals/to-string-tag-support": 138, "../internals/well-known-symbol": 145 }], 30: [function(e, t, r) { - "use strict"; - var u = e("../internals/object-define-property").f, c = e("../internals/object-create"), d = e("../internals/redefine-all"), f = e("../internals/function-bind-context"), h = e("../internals/an-instance"), p = e("../internals/iterate"), a = e("../internals/define-iterator"), s = e("../internals/set-species"), y = e("../internals/descriptors"), m = e("../internals/internal-metadata").fastKey, n = e("../internals/internal-state"), g = n.set, v = n.getterFor; - t.exports = { getConstructor: function(e2, r2, n2, o) { - function i(e3, t2, r3) { - var n3, o2, i2 = s2(e3), a3 = l(e3, t2); - return a3 ? a3.value = r3 : (i2.last = a3 = { index: o2 = m(t2, true), key: t2, value: r3, previous: n3 = i2.last, next: void 0, removed: false }, i2.first || (i2.first = a3), n3 && (n3.next = a3), y ? i2.size++ : e3.size++, o2 !== "F" && (i2.index[o2] = a3)), e3; - } - var a2 = e2(function(e3, t2) { - h(e3, a2, r2), g(e3, { type: r2, index: c(null), first: void 0, last: void 0, size: 0 }), y || (e3.size = 0), t2 != null && p(t2, e3[o], e3, n2); - }), s2 = v(r2), l = function(e3, t2) { - var r3, n3 = s2(e3), o2 = m(t2); - if (o2 !== "F") - return n3.index[o2]; - for (r3 = n3.first; r3; r3 = r3.next) - if (r3.key == t2) - return r3; - }; - return d(a2.prototype, { clear: function() { - for (var e3 = s2(this), t2 = e3.index, r3 = e3.first; r3; ) - r3.removed = true, r3.previous && (r3.previous = r3.previous.next = void 0), delete t2[r3.index], r3 = r3.next; - e3.first = e3.last = void 0, y ? e3.size = 0 : this.size = 0; - }, delete: function(e3) { - var t2 = s2(this), r3 = l(this, e3); - if (r3) { - var n3 = r3.next, o2 = r3.previous; - delete t2.index[r3.index], r3.removed = true, o2 && (o2.next = n3), n3 && (n3.previous = o2), t2.first == r3 && (t2.first = n3), t2.last == r3 && (t2.last = o2), y ? t2.size-- : this.size--; - } - return !!r3; - }, forEach: function(e3, t2) { - for (var r3, n3 = s2(this), o2 = f(e3, 1 < arguments.length ? t2 : void 0, 3); r3 = r3 ? r3.next : n3.first; ) - for (o2(r3.value, r3.key, this); r3 && r3.removed; ) - r3 = r3.previous; - }, has: function(e3) { - return !!l(this, e3); - } }), d(a2.prototype, n2 ? { get: function(e3) { - var t2 = l(this, e3); - return t2 && t2.value; - }, set: function(e3, t2) { - return i(this, e3 === 0 ? 0 : e3, t2); - } } : { add: function(e3) { - return i(this, e3 = e3 === 0 ? 0 : e3, e3); - } }), y && u(a2.prototype, "size", { get: function() { - return s2(this).size; - } }), a2; - }, setStrong: function(e2, t2, r2) { - var n2 = t2 + " Iterator", o = v(t2), i = v(n2); - a(e2, t2, function(e3, t3) { - g(this, { type: n2, target: e3, state: o(e3), kind: t3, last: void 0 }); - }, function() { - for (var e3 = i(this), t3 = e3.kind, r3 = e3.last; r3 && r3.removed; ) - r3 = r3.previous; - return e3.target && (e3.last = r3 = r3 ? r3.next : e3.state.first) ? t3 == "keys" ? { value: r3.key, done: false } : t3 == "values" ? { value: r3.value, done: false } : { value: [r3.key, r3.value], done: false } : { value: e3.target = void 0, done: true }; - }, r2 ? "entries" : "values", !r2, true), s(t2); - } }; - }, { "../internals/an-instance": 9, "../internals/define-iterator": 40, "../internals/descriptors": 42, "../internals/function-bind-context": 53, "../internals/internal-metadata": 68, "../internals/internal-state": 69, "../internals/iterate": 76, "../internals/object-create": 89, "../internals/object-define-property": 91, "../internals/redefine-all": 106, "../internals/set-species": 115 }], 31: [function(e, t, r) { - "use strict"; - var m = e("../internals/export"), g = e("../internals/global"), v = e("../internals/is-forced"), b = e("../internals/redefine"), _ = e("../internals/internal-metadata"), x = e("../internals/iterate"), w = e("../internals/an-instance"), S = e("../internals/is-object"), j = e("../internals/fails"), M = e("../internals/check-correctness-of-iteration"), E = e("../internals/set-to-string-tag"), T = e("../internals/inherit-if-required"); - t.exports = function(n, e2, t2) { - function r2(e3) { - var r3 = l[e3]; - b(l, e3, e3 == "add" ? function(e4) { - return r3.call(this, e4 === 0 ? 0 : e4), this; - } : e3 == "delete" ? function(e4) { - return !(i && !S(e4)) && r3.call(this, e4 === 0 ? 0 : e4); - } : e3 == "get" ? function(e4) { - return i && !S(e4) ? void 0 : r3.call(this, e4 === 0 ? 0 : e4); - } : e3 == "has" ? function(e4) { - return !(i && !S(e4)) && r3.call(this, e4 === 0 ? 0 : e4); - } : function(e4, t3) { - return r3.call(this, e4 === 0 ? 0 : e4, t3), this; - }); - } - var o = n.indexOf("Map") !== -1, i = n.indexOf("Weak") !== -1, a = o ? "set" : "add", s = g[n], l = s && s.prototype, u = s, c = {}; - if (v(n, typeof s != "function" || !(i || l.forEach && !j(function() { - new s().entries().next(); - })))) - u = t2.getConstructor(e2, n, o, a), _.REQUIRED = true; - else if (v(n, true)) { - var d = new u(), f = d[a](i ? {} : -0, 1) != d, h = j(function() { - d.has(1); - }), p = M(function(e3) { - new s(e3); - }), y = !i && j(function() { - for (var e3 = new s(), t3 = 5; t3--; ) - e3[a](t3, t3); - return !e3.has(-0); - }); - p || (((u = e2(function(e3, t3) { - w(e3, u, n); - var r3 = T(new s(), e3, u); - return t3 != null && x(t3, r3[a], r3, o), r3; - })).prototype = l).constructor = u), (h || y) && (r2("delete"), r2("has"), o && r2("get")), (y || f) && r2(a), i && l.clear && delete l.clear; - } - return c[n] = u, m({ global: true, forced: u != s }, c), E(u, n), i || t2.setStrong(u, n, o), u; - }; - }, { "../internals/an-instance": 9, "../internals/check-correctness-of-iteration": 27, "../internals/export": 49, "../internals/fails": 50, "../internals/global": 58, "../internals/inherit-if-required": 66, "../internals/internal-metadata": 68, "../internals/is-forced": 72, "../internals/is-object": 73, "../internals/iterate": 76, "../internals/redefine": 107, "../internals/set-to-string-tag": 116 }], 32: [function(e, t, r) { - var s = e("../internals/has"), l = e("../internals/own-keys"), u = e("../internals/object-get-own-property-descriptor"), c = e("../internals/object-define-property"); - t.exports = function(e2, t2) { - for (var r2 = l(t2), n = c.f, o = u.f, i = 0; i < r2.length; i++) { - var a = r2[i]; - s(e2, a) || n(e2, a, o(t2, a)); - } - }; - }, { "../internals/has": 59, "../internals/object-define-property": 91, "../internals/object-get-own-property-descriptor": 92, "../internals/own-keys": 102 }], 33: [function(e, t, r) { - var n = e("../internals/well-known-symbol")("match"); - t.exports = function(t2) { - var r2 = /./; - try { - "/./"[t2](r2); - } catch (e2) { - try { - return r2[n] = false, "/./"[t2](r2); - } catch (e3) { - } - } - return false; - }; - }, { "../internals/well-known-symbol": 145 }], 34: [function(e, t, r) { - var n = e("../internals/fails"); - t.exports = !n(function() { - function e2() { - } - return e2.prototype.constructor = null, Object.getPrototypeOf(new e2()) !== e2.prototype; - }); - }, { "../internals/fails": 50 }], 35: [function(e, t, r) { - var a = e("../internals/require-object-coercible"), s = /"/g; - t.exports = function(e2, t2, r2, n) { - var o = String(a(e2)), i = "<" + t2; - return r2 !== "" && (i += " " + r2 + '="' + String(n).replace(s, """) + '"'), i + ">" + o + ""; - }; - }, { "../internals/require-object-coercible": 112 }], 36: [function(e, t, r) { - "use strict"; - function o() { - return this; - } - var i = e("../internals/iterators-core").IteratorPrototype, a = e("../internals/object-create"), s = e("../internals/create-property-descriptor"), l = e("../internals/set-to-string-tag"), u = e("../internals/iterators"); - t.exports = function(e2, t2, r2) { - var n = t2 + " Iterator"; - return e2.prototype = a(i, { next: s(1, r2) }), l(e2, n, false, true), u[n] = o, e2; - }; - }, { "../internals/create-property-descriptor": 38, "../internals/iterators": 78, "../internals/iterators-core": 77, "../internals/object-create": 89, "../internals/set-to-string-tag": 116 }], 37: [function(e, t, r) { - var n = e("../internals/descriptors"), o = e("../internals/object-define-property"), i = e("../internals/create-property-descriptor"); - t.exports = n ? function(e2, t2, r2) { - return o.f(e2, t2, i(1, r2)); - } : function(e2, t2, r2) { - return e2[t2] = r2, e2; - }; - }, { "../internals/create-property-descriptor": 38, "../internals/descriptors": 42, "../internals/object-define-property": 91 }], 38: [function(e, t, r) { - t.exports = function(e2, t2) { - return { enumerable: !(1 & e2), configurable: !(2 & e2), writable: !(4 & e2), value: t2 }; - }; - }, {}], 39: [function(e, t, r) { - "use strict"; - var o = e("../internals/to-primitive"), i = e("../internals/object-define-property"), a = e("../internals/create-property-descriptor"); - t.exports = function(e2, t2, r2) { - var n = o(t2); - n in e2 ? i.f(e2, n, a(0, r2)) : e2[n] = r2; - }; - }, { "../internals/create-property-descriptor": 38, "../internals/object-define-property": 91, "../internals/to-primitive": 137 }], 40: [function(e, t, r) { - "use strict"; - function g() { - return this; - } - var v = e("../internals/export"), b = e("../internals/create-iterator-constructor"), _ = e("../internals/object-get-prototype-of"), x = e("../internals/object-set-prototype-of"), w = e("../internals/set-to-string-tag"), S = e("../internals/create-non-enumerable-property"), j = e("../internals/redefine"), n = e("../internals/well-known-symbol"), M = e("../internals/is-pure"), E = e("../internals/iterators"), o = e("../internals/iterators-core"), T = o.IteratorPrototype, O = o.BUGGY_SAFARI_ITERATORS, C = n("iterator"), L = "values", P = "entries"; - t.exports = function(e2, t2, r2, n2, o2, i, a) { - b(r2, t2, n2); - function s(e3) { - if (e3 === o2 && y) - return y; - if (!O && e3 in h) - return h[e3]; - switch (e3) { - case "keys": - case L: - case P: - return function() { - return new r2(this, e3); - }; - } - return function() { - return new r2(this); - }; - } - var l, u, c, d = t2 + " Iterator", f = false, h = e2.prototype, p = h[C] || h["@@iterator"] || o2 && h[o2], y = !O && p || s(o2), m = t2 == "Array" && h.entries || p; - if (m && (l = _(m.call(new e2())), T !== Object.prototype && l.next && (M || _(l) === T || (x ? x(l, T) : typeof l[C] != "function" && S(l, C, g)), w(l, d, true, true), M && (E[d] = g))), o2 == L && p && p.name !== L && (f = true, y = function() { - return p.call(this); - }), M && !a || h[C] === y || S(h, C, y), E[t2] = y, o2) - if (u = { values: s(L), keys: i ? y : s("keys"), entries: s(P) }, a) - for (c in u) - !O && !f && c in h || j(h, c, u[c]); - else - v({ target: t2, proto: true, forced: O || f }, u); - return u; - }; - }, { "../internals/create-iterator-constructor": 36, "../internals/create-non-enumerable-property": 37, "../internals/export": 49, "../internals/is-pure": 74, "../internals/iterators": 78, "../internals/iterators-core": 77, "../internals/object-get-prototype-of": 96, "../internals/object-set-prototype-of": 100, "../internals/redefine": 107, "../internals/set-to-string-tag": 116, "../internals/well-known-symbol": 145 }], 41: [function(e, t, r) { - var n = e("../internals/path"), o = e("../internals/has"), i = e("../internals/well-known-symbol-wrapped"), a = e("../internals/object-define-property").f; - t.exports = function(e2) { - var t2 = n.Symbol || (n.Symbol = {}); - o(t2, e2) || a(t2, e2, { value: i.f(e2) }); - }; - }, { "../internals/has": 59, "../internals/object-define-property": 91, "../internals/path": 103, "../internals/well-known-symbol-wrapped": 144 }], 42: [function(e, t, r) { - var n = e("../internals/fails"); - t.exports = !n(function() { - return Object.defineProperty({}, 1, { get: function() { - return 7; - } })[1] != 7; - }); - }, { "../internals/fails": 50 }], 43: [function(e, t, r) { - var n = e("../internals/global"), o = e("../internals/is-object"), i = n.document, a = o(i) && o(i.createElement); - t.exports = function(e2) { - return a ? i.createElement(e2) : {}; - }; - }, { "../internals/global": 58, "../internals/is-object": 73 }], 44: [function(e, t, r) { - t.exports = { CSSRuleList: 0, CSSStyleDeclaration: 0, CSSValueList: 0, ClientRectList: 0, DOMRectList: 0, DOMStringList: 0, DOMTokenList: 1, DataTransferItemList: 0, FileList: 0, HTMLAllCollection: 0, HTMLCollection: 0, HTMLFormElement: 0, HTMLSelectElement: 0, MediaList: 0, MimeTypeArray: 0, NamedNodeMap: 0, NodeList: 1, PaintRequestList: 0, Plugin: 0, PluginArray: 0, SVGLengthList: 0, SVGNumberList: 0, SVGPathSegList: 0, SVGPointList: 0, SVGStringList: 0, SVGTransformList: 0, SourceBufferList: 0, StyleSheetList: 0, TextTrackCueList: 0, TextTrackList: 0, TouchList: 0 }; - }, {}], 45: [function(e, t, r) { - var n = e("../internals/engine-user-agent"); - t.exports = /(iphone|ipod|ipad).*applewebkit/i.test(n); - }, { "../internals/engine-user-agent": 46 }], 46: [function(e, t, r) { - var n = e("../internals/get-built-in"); - t.exports = n("navigator", "userAgent") || ""; - }, { "../internals/get-built-in": 55 }], 47: [function(e, t, r) { - var n, o, i = e("../internals/global"), a = e("../internals/engine-user-agent"), s = i.process, l = s && s.versions, u = l && l.v8; - u ? o = (n = u.split("."))[0] + n[1] : a && (!(n = a.match(/Edge\/(\d+)/)) || 74 <= n[1]) && (n = a.match(/Chrome\/(\d+)/)) && (o = n[1]), t.exports = o && +o; - }, { "../internals/engine-user-agent": 46, "../internals/global": 58 }], 48: [function(e, t, r) { - t.exports = ["constructor", "hasOwnProperty", "isPrototypeOf", "propertyIsEnumerable", "toLocaleString", "toString", "valueOf"]; - }, {}], 49: [function(e, t, r) { - var c = e("../internals/global"), d = e("../internals/object-get-own-property-descriptor").f, f = e("../internals/create-non-enumerable-property"), h = e("../internals/redefine"), p = e("../internals/set-global"), y = e("../internals/copy-constructor-properties"), m = e("../internals/is-forced"); - t.exports = function(e2, t2) { - var r2, n, o, i, a, s = e2.target, l = e2.global, u = e2.stat; - if (r2 = l ? c : u ? c[s] || p(s, {}) : (c[s] || {}).prototype) - for (n in t2) { - if (i = t2[n], o = e2.noTargetGet ? (a = d(r2, n)) && a.value : r2[n], !m(l ? n : s + (u ? "." : "#") + n, e2.forced) && o !== void 0) { - if (typeof i == typeof o) - continue; - y(i, o); - } - (e2.sham || o && o.sham) && f(i, "sham", true), h(r2, n, i, e2); - } - }; - }, { "../internals/copy-constructor-properties": 32, "../internals/create-non-enumerable-property": 37, "../internals/global": 58, "../internals/is-forced": 72, "../internals/object-get-own-property-descriptor": 92, "../internals/redefine": 107, "../internals/set-global": 114 }], 50: [function(e, t, r) { - t.exports = function(e2) { - try { - return !!e2(); - } catch (e3) { - return true; - } - }; - }, {}], 51: [function(e, t, r) { - "use strict"; - e("../modules/es.regexp.exec"); - var d = e("../internals/redefine"), f = e("../internals/fails"), h = e("../internals/well-known-symbol"), p = e("../internals/regexp-exec"), y = e("../internals/create-non-enumerable-property"), m = h("species"), g = !f(function() { - var e2 = /./; - return e2.exec = function() { - var e3 = []; - return e3.groups = { a: "7" }, e3; - }, "".replace(e2, "$") !== "7"; - }), v = "a".replace(/./, "$0") === "$0", n = h("replace"), b = !!/./[n] && /./[n]("a", "$0") === "", _ = !f(function() { - var e2 = /(?:)/, t2 = e2.exec; - e2.exec = function() { - return t2.apply(this, arguments); - }; - var r2 = "ab".split(e2); - return r2.length !== 2 || r2[0] !== "a" || r2[1] !== "b"; - }); - t.exports = function(r2, e2, t2, n2) { - var o = h(r2), i = !f(function() { - var e3 = {}; - return e3[o] = function() { - return 7; - }, ""[r2](e3) != 7; - }), a = i && !f(function() { - var e3 = false, t3 = /a/; - return r2 === "split" && ((t3 = { constructor: {} }).constructor[m] = function() { - return t3; - }, t3.flags = "", t3[o] = /./[o]), t3.exec = function() { - return e3 = true, null; - }, t3[o](""), !e3; - }); - if (!i || !a || r2 === "replace" && (!g || !v || b) || r2 === "split" && !_) { - var s = /./[o], l = t2(o, ""[r2], function(e3, t3, r3, n3, o2) { - return t3.exec === p ? i && !o2 ? { done: true, value: s.call(t3, r3, n3) } : { done: true, value: e3.call(r3, t3, n3) } : { done: false }; - }, { REPLACE_KEEPS_$0: v, REGEXP_REPLACE_SUBSTITUTES_UNDEFINED_CAPTURE: b }), u = l[0], c = l[1]; - d(String.prototype, r2, u), d(RegExp.prototype, o, e2 == 2 ? function(e3, t3) { - return c.call(e3, this, t3); - } : function(e3) { - return c.call(e3, this); - }); - } - n2 && y(RegExp.prototype[o], "sham", true); - }; - }, { "../internals/create-non-enumerable-property": 37, "../internals/fails": 50, "../internals/redefine": 107, "../internals/regexp-exec": 109, "../internals/well-known-symbol": 145, "../modules/es.regexp.exec": 178 }], 52: [function(e, t, r) { - var n = e("../internals/fails"); - t.exports = !n(function() { - return Object.isExtensible(Object.preventExtensions({})); - }); - }, { "../internals/fails": 50 }], 53: [function(e, t, r) { - var i = e("../internals/a-function"); - t.exports = function(n, o, e2) { - if (i(n), o === void 0) - return n; - switch (e2) { - case 0: - return function() { - return n.call(o); - }; - case 1: - return function(e3) { - return n.call(o, e3); - }; - case 2: - return function(e3, t2) { - return n.call(o, e3, t2); - }; - case 3: - return function(e3, t2, r2) { - return n.call(o, e3, t2, r2); - }; - } - return function() { - return n.apply(o, arguments); - }; - }; - }, { "../internals/a-function": 5 }], 54: [function(e, t, r) { - "use strict"; - var i = e("../internals/a-function"), a = e("../internals/is-object"), s = [].slice, l = {}; - t.exports = Function.bind || function(t2) { - var r2 = i(this), n = s.call(arguments, 1), o = function() { - var e2 = n.concat(s.call(arguments)); - return this instanceof o ? function(e3, t3, r3) { - if (!(t3 in l)) { - for (var n2 = [], o2 = 0; o2 < t3; o2++) - n2[o2] = "a[" + o2 + "]"; - l[t3] = Function("C,a", "return new C(" + n2.join(",") + ")"); - } - return l[t3](e3, r3); - }(r2, e2.length, e2) : r2.apply(t2, e2); - }; - return a(r2.prototype) && (o.prototype = r2.prototype), o; - }; - }, { "../internals/a-function": 5, "../internals/is-object": 73 }], 55: [function(e, t, r) { - function n(e2) { - return typeof e2 == "function" ? e2 : void 0; - } - var o = e("../internals/path"), i = e("../internals/global"); - t.exports = function(e2, t2) { - return arguments.length < 2 ? n(o[e2]) || n(i[e2]) : o[e2] && o[e2][t2] || i[e2] && i[e2][t2]; - }; - }, { "../internals/global": 58, "../internals/path": 103 }], 56: [function(e, t, r) { - var n = e("../internals/classof"), o = e("../internals/iterators"), i = e("../internals/well-known-symbol")("iterator"); - t.exports = function(e2) { - if (e2 != null) - return e2[i] || e2["@@iterator"] || o[n(e2)]; - }; - }, { "../internals/classof": 29, "../internals/iterators": 78, "../internals/well-known-symbol": 145 }], 57: [function(e, t, r) { - var n = e("../internals/an-object"), o = e("../internals/get-iterator-method"); - t.exports = function(e2) { - var t2 = o(e2); - if (typeof t2 != "function") - throw TypeError(String(e2) + " is not iterable"); - return n(t2.call(e2)); - }; - }, { "../internals/an-object": 10, "../internals/get-iterator-method": 56 }], 58: [function(e, r, t) { - (function(e2) { - function t2(e3) { - return e3 && e3.Math == Math && e3; - } - r.exports = t2(typeof globalThis == "object" && globalThis) || t2(typeof window == "object" && window) || t2(typeof self == "object" && self) || t2(typeof e2 == "object" && e2) || Function("return this")(); - }).call(this, typeof global != "undefined" ? global : typeof self != "undefined" ? self : typeof window != "undefined" ? window : {}); - }, {}], 59: [function(e, t, r) { - var n = {}.hasOwnProperty; - t.exports = function(e2, t2) { - return n.call(e2, t2); - }; - }, {}], 60: [function(e, t, r) { - t.exports = {}; - }, {}], 61: [function(e, t, r) { - var n = e("../internals/global"); - t.exports = function(e2, t2) { - var r2 = n.console; - r2 && r2.error && (arguments.length === 1 ? r2.error(e2) : r2.error(e2, t2)); - }; - }, { "../internals/global": 58 }], 62: [function(e, t, r) { - var n = e("../internals/get-built-in"); - t.exports = n("document", "documentElement"); - }, { "../internals/get-built-in": 55 }], 63: [function(e, t, r) { - var n = e("../internals/descriptors"), o = e("../internals/fails"), i = e("../internals/document-create-element"); - t.exports = !n && !o(function() { - return Object.defineProperty(i("div"), "a", { get: function() { - return 7; - } }).a != 7; - }); - }, { "../internals/descriptors": 42, "../internals/document-create-element": 43, "../internals/fails": 50 }], 64: [function(e, t, r) { - var h = Math.abs, p = Math.pow, y = Math.floor, m = Math.log, g = Math.LN2; - t.exports = { pack: function(e2, t2, r2) { - var n, o, i, a = new Array(r2), s = 8 * r2 - t2 - 1, l = (1 << s) - 1, u = l >> 1, c = t2 === 23 ? p(2, -24) - p(2, -77) : 0, d = e2 < 0 || e2 === 0 && 1 / e2 < 0 ? 1 : 0, f = 0; - for ((e2 = h(e2)) != e2 || e2 === 1 / 0 ? (o = e2 != e2 ? 1 : 0, n = l) : (n = y(m(e2) / g), e2 * (i = p(2, -n)) < 1 && (n--, i *= 2), 2 <= (e2 += 1 <= n + u ? c / i : c * p(2, 1 - u)) * i && (n++, i /= 2), l <= n + u ? (o = 0, n = l) : 1 <= n + u ? (o = (e2 * i - 1) * p(2, t2), n += u) : (o = e2 * p(2, u - 1) * p(2, t2), n = 0)); 8 <= t2; a[f++] = 255 & o, o /= 256, t2 -= 8) - ; - for (n = n << t2 | o, s += t2; 0 < s; a[f++] = 255 & n, n /= 256, s -= 8) - ; - return a[--f] |= 128 * d, a; - }, unpack: function(e2, t2) { - var r2, n = e2.length, o = 8 * n - t2 - 1, i = (1 << o) - 1, a = i >> 1, s = o - 7, l = n - 1, u = e2[l--], c = 127 & u; - for (u >>= 7; 0 < s; c = 256 * c + e2[l], l--, s -= 8) - ; - for (r2 = c & (1 << -s) - 1, c >>= -s, s += t2; 0 < s; r2 = 256 * r2 + e2[l], l--, s -= 8) - ; - if (c === 0) - c = 1 - a; - else { - if (c === i) - return r2 ? NaN : u ? -1 / 0 : 1 / 0; - r2 += p(2, t2), c -= a; - } - return (u ? -1 : 1) * r2 * p(2, c - t2); - } }; - }, {}], 65: [function(e, t, r) { - var n = e("../internals/fails"), o = e("../internals/classof-raw"), i = "".split; - t.exports = n(function() { - return !Object("z").propertyIsEnumerable(0); - }) ? function(e2) { - return o(e2) == "String" ? i.call(e2, "") : Object(e2); - } : Object; - }, { "../internals/classof-raw": 28, "../internals/fails": 50 }], 66: [function(e, t, r) { - var i = e("../internals/is-object"), a = e("../internals/object-set-prototype-of"); - t.exports = function(e2, t2, r2) { - var n, o; - return a && typeof (n = t2.constructor) == "function" && n !== r2 && i(o = n.prototype) && o !== r2.prototype && a(e2, o), e2; - }; - }, { "../internals/is-object": 73, "../internals/object-set-prototype-of": 100 }], 67: [function(e, t, r) { - var n = e("../internals/shared-store"), o = Function.toString; - typeof n.inspectSource != "function" && (n.inspectSource = function(e2) { - return o.call(e2); - }), t.exports = n.inspectSource; - }, { "../internals/shared-store": 118 }], 68: [function(e, t, r) { - function n(e2) { - s(e2, c, { value: { objectID: "O" + ++d, weakData: {} } }); - } - var o = e("../internals/hidden-keys"), i = e("../internals/is-object"), a = e("../internals/has"), s = e("../internals/object-define-property").f, l = e("../internals/uid"), u = e("../internals/freezing"), c = l("meta"), d = 0, f = Object.isExtensible || function() { - return true; - }, h = t.exports = { REQUIRED: false, fastKey: function(e2, t2) { - if (!i(e2)) - return typeof e2 == "symbol" ? e2 : (typeof e2 == "string" ? "S" : "P") + e2; - if (!a(e2, c)) { - if (!f(e2)) - return "F"; - if (!t2) - return "E"; - n(e2); - } - return e2[c].objectID; - }, getWeakData: function(e2, t2) { - if (!a(e2, c)) { - if (!f(e2)) - return true; - if (!t2) - return false; - n(e2); - } - return e2[c].weakData; - }, onFreeze: function(e2) { - return u && h.REQUIRED && f(e2) && !a(e2, c) && n(e2), e2; - } }; - o[c] = true; - }, { "../internals/freezing": 52, "../internals/has": 59, "../internals/hidden-keys": 60, "../internals/is-object": 73, "../internals/object-define-property": 91, "../internals/uid": 142 }], 69: [function(e, t, r) { - var n, o, i, a = e("../internals/native-weak-map"), s = e("../internals/global"), l = e("../internals/is-object"), u = e("../internals/create-non-enumerable-property"), c = e("../internals/has"), d = e("../internals/shared-key"), f = e("../internals/hidden-keys"), h = s.WeakMap; - if (a) { - var p = new h(), y = p.get, m = p.has, g = p.set; - n = function(e2, t2) { - return g.call(p, e2, t2), t2; - }, o = function(e2) { - return y.call(p, e2) || {}; - }, i = function(e2) { - return m.call(p, e2); - }; - } else { - var v = d("state"); - f[v] = true, n = function(e2, t2) { - return u(e2, v, t2), t2; - }, o = function(e2) { - return c(e2, v) ? e2[v] : {}; - }, i = function(e2) { - return c(e2, v); - }; - } - t.exports = { set: n, get: o, has: i, enforce: function(e2) { - return i(e2) ? o(e2) : n(e2, {}); - }, getterFor: function(r2) { - return function(e2) { - var t2; - if (!l(e2) || (t2 = o(e2)).type !== r2) - throw TypeError("Incompatible receiver, " + r2 + " required"); - return t2; - }; - } }; - }, { "../internals/create-non-enumerable-property": 37, "../internals/global": 58, "../internals/has": 59, "../internals/hidden-keys": 60, "../internals/is-object": 73, "../internals/native-weak-map": 84, "../internals/shared-key": 117 }], 70: [function(e, t, r) { - var n = e("../internals/well-known-symbol"), o = e("../internals/iterators"), i = n("iterator"), a = Array.prototype; - t.exports = function(e2) { - return e2 !== void 0 && (o.Array === e2 || a[i] === e2); - }; - }, { "../internals/iterators": 78, "../internals/well-known-symbol": 145 }], 71: [function(e, t, r) { - var n = e("../internals/classof-raw"); - t.exports = Array.isArray || function(e2) { - return n(e2) == "Array"; - }; - }, { "../internals/classof-raw": 28 }], 72: [function(e, t, r) { - function n(e2, t2) { - var r2 = s[a(e2)]; - return r2 == u || r2 != l && (typeof t2 == "function" ? o(t2) : !!t2); - } - var o = e("../internals/fails"), i = /#|\.prototype\./, a = n.normalize = function(e2) { - return String(e2).replace(i, ".").toLowerCase(); - }, s = n.data = {}, l = n.NATIVE = "N", u = n.POLYFILL = "P"; - t.exports = n; - }, { "../internals/fails": 50 }], 73: [function(e, t, r) { - t.exports = function(e2) { - return typeof e2 == "object" ? e2 !== null : typeof e2 == "function"; - }; - }, {}], 74: [function(e, t, r) { - t.exports = false; - }, {}], 75: [function(e, t, r) { - var n = e("../internals/is-object"), o = e("../internals/classof-raw"), i = e("../internals/well-known-symbol")("match"); - t.exports = function(e2) { - var t2; - return n(e2) && ((t2 = e2[i]) !== void 0 ? !!t2 : o(e2) == "RegExp"); - }; - }, { "../internals/classof-raw": 28, "../internals/is-object": 73, "../internals/well-known-symbol": 145 }], 76: [function(e, t, r) { - function h(e2, t2) { - this.stopped = e2, this.result = t2; - } - var p = e("../internals/an-object"), y = e("../internals/is-array-iterator-method"), m = e("../internals/to-length"), g = e("../internals/function-bind-context"), v = e("../internals/get-iterator-method"), b = e("../internals/call-with-safe-iteration-closing"); - (t.exports = function(e2, t2, r2, n, o) { - var i, a, s, l, u, c, d, f = g(t2, r2, n ? 2 : 1); - if (o) - i = e2; - else { - if (typeof (a = v(e2)) != "function") - throw TypeError("Target is not iterable"); - if (y(a)) { - for (s = 0, l = m(e2.length); s < l; s++) - if ((u = n ? f(p(d = e2[s])[0], d[1]) : f(e2[s])) && u instanceof h) - return u; - return new h(false); - } - i = a.call(e2); - } - for (c = i.next; !(d = c.call(i)).done; ) - if (typeof (u = b(i, f, d.value, n)) == "object" && u && u instanceof h) - return u; - return new h(false); - }).stop = function(e2) { - return new h(true, e2); - }; - }, { "../internals/an-object": 10, "../internals/call-with-safe-iteration-closing": 26, "../internals/function-bind-context": 53, "../internals/get-iterator-method": 56, "../internals/is-array-iterator-method": 70, "../internals/to-length": 133 }], 77: [function(e, t, r) { - "use strict"; - var n, o, i, a = e("../internals/object-get-prototype-of"), s = e("../internals/create-non-enumerable-property"), l = e("../internals/has"), u = e("../internals/well-known-symbol"), c = e("../internals/is-pure"), d = u("iterator"), f = false; - [].keys && ("next" in (i = [].keys()) ? (o = a(a(i))) !== Object.prototype && (n = o) : f = true), n == null && (n = {}), c || l(n, d) || s(n, d, function() { - return this; - }), t.exports = { IteratorPrototype: n, BUGGY_SAFARI_ITERATORS: f }; - }, { "../internals/create-non-enumerable-property": 37, "../internals/has": 59, "../internals/is-pure": 74, "../internals/object-get-prototype-of": 96, "../internals/well-known-symbol": 145 }], 78: [function(e, t, r) { - arguments[4][60][0].apply(r, arguments); - }, { dup: 60 }], 79: [function(e, t, r) { - t.exports = Math.sign || function(e2) { - return (e2 = +e2) == 0 || e2 != e2 ? e2 : e2 < 0 ? -1 : 1; - }; - }, {}], 80: [function(e, t, r) { - var n, o, i, a, s, l, u, c, d = e("../internals/global"), f = e("../internals/object-get-own-property-descriptor").f, h = e("../internals/classof-raw"), p = e("../internals/task").set, y = e("../internals/engine-is-ios"), m = d.MutationObserver || d.WebKitMutationObserver, g = d.process, v = d.Promise, b = h(g) == "process", _ = f(d, "queueMicrotask"), x = _ && _.value; - x || (n = function() { - var e2, t2; - for (b && (e2 = g.domain) && e2.exit(); o; ) { - t2 = o.fn, o = o.next; - try { - t2(); - } catch (e3) { - throw o ? a() : i = void 0, e3; - } - } - i = void 0, e2 && e2.enter(); - }, a = b ? function() { - g.nextTick(n); - } : m && !y ? (s = true, l = document.createTextNode(""), new m(n).observe(l, { characterData: true }), function() { - l.data = s = !s; - }) : v && v.resolve ? (u = v.resolve(void 0), c = u.then, function() { - c.call(u, n); - }) : function() { - p.call(d, n); - }), t.exports = x || function(e2) { - var t2 = { fn: e2, next: void 0 }; - i && (i.next = t2), o || (o = t2, a()), i = t2; - }; - }, { "../internals/classof-raw": 28, "../internals/engine-is-ios": 45, "../internals/global": 58, "../internals/object-get-own-property-descriptor": 92, "../internals/task": 127 }], 81: [function(e, t, r) { - var n = e("../internals/global"); - t.exports = n.Promise; - }, { "../internals/global": 58 }], 82: [function(e, t, r) { - var n = e("../internals/fails"); - t.exports = !!Object.getOwnPropertySymbols && !n(function() { - return !String(Symbol()); - }); - }, { "../internals/fails": 50 }], 83: [function(e, t, r) { - var n = e("../internals/fails"), o = e("../internals/well-known-symbol"), i = e("../internals/is-pure"), a = o("iterator"); - t.exports = !n(function() { - var e2 = new URL("b?a=1&b=2&c=3", "http://a"), r2 = e2.searchParams, n2 = ""; - return e2.pathname = "c%20d", r2.forEach(function(e3, t2) { - r2.delete("b"), n2 += t2 + e3; - }), i && !e2.toJSON || !r2.sort || e2.href !== "http://a/c%20d?a=1&c=3" || r2.get("c") !== "3" || String(new URLSearchParams("?a=1")) !== "a=1" || !r2[a] || new URL("https://a@b").username !== "a" || new URLSearchParams(new URLSearchParams("a=b")).get("a") !== "b" || new URL("http://\u0442\u0435\u0441\u0442").host !== "xn--e1aybc" || new URL("http://a#\u0431").hash !== "#%D0%B1" || n2 !== "a1c3" || new URL("http://x", void 0).host !== "x"; - }); - }, { "../internals/fails": 50, "../internals/is-pure": 74, "../internals/well-known-symbol": 145 }], 84: [function(e, t, r) { - var n = e("../internals/global"), o = e("../internals/inspect-source"), i = n.WeakMap; - t.exports = typeof i == "function" && /native code/.test(o(i)); - }, { "../internals/global": 58, "../internals/inspect-source": 67 }], 85: [function(e, t, r) { - "use strict"; - function n(e2) { - var r2, n2; - this.promise = new e2(function(e3, t2) { - if (r2 !== void 0 || n2 !== void 0) - throw TypeError("Bad Promise constructor"); - r2 = e3, n2 = t2; - }), this.resolve = o(r2), this.reject = o(n2); - } - var o = e("../internals/a-function"); - t.exports.f = function(e2) { - return new n(e2); - }; - }, { "../internals/a-function": 5 }], 86: [function(e, t, r) { - var n = e("../internals/is-regexp"); - t.exports = function(e2) { - if (n(e2)) - throw TypeError("The method doesn't accept regular expressions"); - return e2; - }; - }, { "../internals/is-regexp": 75 }], 87: [function(e, t, r) { - var n = e("../internals/global").isFinite; - t.exports = Number.isFinite || function(e2) { - return typeof e2 == "number" && n(e2); - }; - }, { "../internals/global": 58 }], 88: [function(e, t, r) { - "use strict"; - var f = e("../internals/descriptors"), n = e("../internals/fails"), h = e("../internals/object-keys"), p = e("../internals/object-get-own-property-symbols"), y = e("../internals/object-property-is-enumerable"), m = e("../internals/to-object"), g = e("../internals/indexed-object"), o = Object.assign, i = Object.defineProperty; - t.exports = !o || n(function() { - if (f && o({ b: 1 }, o(i({}, "a", { enumerable: true, get: function() { - i(this, "b", { value: 3, enumerable: false }); - } }), { b: 2 })).b !== 1) - return true; - var e2 = {}, t2 = {}, r2 = Symbol(), n2 = "abcdefghijklmnopqrst"; - return e2[r2] = 7, n2.split("").forEach(function(e3) { - t2[e3] = e3; - }), o({}, e2)[r2] != 7 || h(o({}, t2)).join("") != n2; - }) ? function(e2, t2) { - for (var r2 = m(e2), n2 = arguments.length, o2 = 1, i2 = p.f, a = y.f; o2 < n2; ) - for (var s, l = g(arguments[o2++]), u = i2 ? h(l).concat(i2(l)) : h(l), c = u.length, d = 0; d < c; ) - s = u[d++], f && !a.call(l, s) || (r2[s] = l[s]); - return r2; - } : o; - }, { "../internals/descriptors": 42, "../internals/fails": 50, "../internals/indexed-object": 65, "../internals/object-get-own-property-symbols": 95, "../internals/object-keys": 98, "../internals/object-property-is-enumerable": 99, "../internals/to-object": 134 }], 89: [function(e, t, r) { - function n() { - } - function o(e2) { - return " - - -``` - -#### Usage -```js -const data = { - labels: ["12am-3am", "3am-6pm", "6am-9am", "9am-12am", - "12pm-3pm", "3pm-6pm", "6pm-9pm", "9am-12am" - ], - datasets: [ - { - name: "Some Data", type: "bar", - values: [25, 40, 30, 35, 8, 52, 17, -4] - }, - { - name: "Another Set", type: "line", - values: [25, 50, -10, 15, 18, 32, 27, 14] - } - ] -} - -const chart = new frappe.Chart("#chart", { // or a DOM element, - // new Chart() in case of ES6 module with above usage - title: "My Awesome Chart", - data: data, - type: 'axis-mixed', // or 'bar', 'line', 'scatter', 'pie', 'percentage' - height: 250, - colors: ['#7cd6fd', '#743ee2'] -}) -``` - -Or for es-modules (replace `new frappe.Chart()` with `new Chart()`): -```diff -- const chart = new frappe.Chart("#chart", { -+ const chart = new Chart("#chart", { // or a DOM element, - // new Chart() in case of ES6 module with above usage - title: "My Awesome Chart", - data: data, - type: 'axis-mixed', // or 'bar', 'line', 'scatter', 'pie', 'percentage' - height: 250, - colors: ['#7cd6fd', '#743ee2'] -}) -``` - - -If you want to contribute: - -1. Clone this repo. -2. `cd` into project directory -3. `npm install` -4. `npm run dev` - -#### License -This repository has been released under the [MIT License](LICENSE) - ------------------- -Project maintained by [Frappe](https://frappe.io). -Used in [ERPNext](https://erpnext.com). Read the [blog post](https://medium.com/@pratu16x7/so-we-decided-to-create-our-own-charts-a95cb5032c97). diff --git a/node_modules/frappe-charts/dist/frappe-charts.esm.js b/node_modules/frappe-charts/dist/frappe-charts.esm.js deleted file mode 100644 index 80b7e3c..0000000 --- a/node_modules/frappe-charts/dist/frappe-charts.esm.js +++ /dev/null @@ -1,4108 +0,0 @@ -function $(expr, con) { - return typeof expr === "string"? (con || document).querySelector(expr) : expr || null; -} - - - -$.create = (tag, o) => { - var element = document.createElement(tag); - - for (var i in o) { - var val = o[i]; - - if (i === "inside") { - $(val).appendChild(element); - } - else if (i === "around") { - var ref = $(val); - ref.parentNode.insertBefore(element, ref); - element.appendChild(ref); - - } else if (i === "styles") { - if(typeof val === "object") { - Object.keys(val).map(prop => { - element.style[prop] = val[prop]; - }); - } - } else if (i in element ) { - element[i] = val; - } - else { - element.setAttribute(i, val); - } - } - - return element; -}; - -function getOffset(element) { - let rect = element.getBoundingClientRect(); - return { - // https://stackoverflow.com/a/7436602/6495043 - // rect.top varies with scroll, so we add whatever has been - // scrolled to it to get absolute distance from actual page top - top: rect.top + (document.documentElement.scrollTop || document.body.scrollTop), - left: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft) - }; -} - -// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent -// an element's offsetParent property will return null whenever it, or any of its parents, -// is hidden via the display style property. -function isHidden(el) { - return (el.offsetParent === null); -} - -function isElementInViewport(el) { - // Although straightforward: https://stackoverflow.com/a/7557433/6495043 - var rect = el.getBoundingClientRect(); - - return ( - rect.top >= 0 && - rect.left >= 0 && - rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */ - rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */ - ); -} - -function getElementContentWidth(element) { - var styles = window.getComputedStyle(element); - var padding = parseFloat(styles.paddingLeft) + - parseFloat(styles.paddingRight); - - return element.clientWidth - padding; -} - - - - - -function fire(target, type, properties) { - var evt = document.createEvent("HTMLEvents"); - - evt.initEvent(type, true, true ); - - for (var j in properties) { - evt[j] = properties[j]; - } - - return target.dispatchEvent(evt); -} - -// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/ - -const BASE_MEASURES = { - margins: { - top: 10, - bottom: 10, - left: 20, - right: 20 - }, - paddings: { - top: 20, - bottom: 40, - left: 30, - right: 10 - }, - - baseHeight: 240, - titleHeight: 20, - legendHeight: 30, - - titleFontSize: 12, -}; - -function getTopOffset(m) { - return m.titleHeight + m.margins.top + m.paddings.top; -} - -function getLeftOffset(m) { - return m.margins.left + m.paddings.left; -} - -function getExtraHeight(m) { - let totalExtraHeight = m.margins.top + m.margins.bottom - + m.paddings.top + m.paddings.bottom - + m.titleHeight + m.legendHeight; - return totalExtraHeight; -} - -function getExtraWidth(m) { - let totalExtraWidth = m.margins.left + m.margins.right - + m.paddings.left + m.paddings.right; - - return totalExtraWidth; -} - -const INIT_CHART_UPDATE_TIMEOUT = 700; -const CHART_POST_ANIMATE_TIMEOUT = 400; - -const DEFAULT_AXIS_CHART_TYPE = 'line'; -const AXIS_DATASET_CHART_TYPES = ['line', 'bar']; - -const AXIS_LEGEND_BAR_SIZE = 100; - -const BAR_CHART_SPACE_RATIO = 0.5; -const MIN_BAR_PERCENT_HEIGHT = 0.00; - -const LINE_CHART_DOT_SIZE = 4; -const DOT_OVERLAY_SIZE_INCR = 4; - -const PERCENTAGE_BAR_DEFAULT_HEIGHT = 20; -const PERCENTAGE_BAR_DEFAULT_DEPTH = 2; - -// Fixed 5-color theme, -// More colors are difficult to parse visually -const HEATMAP_DISTRIBUTION_SIZE = 5; - -const HEATMAP_SQUARE_SIZE = 10; -const HEATMAP_GUTTER_SIZE = 2; - -const DEFAULT_CHAR_WIDTH = 7; - -const TOOLTIP_POINTER_TRIANGLE_HEIGHT = 5; - -const DEFAULT_CHART_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange', - 'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey']; -const HEATMAP_COLORS_GREEN = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']; - - - -const DEFAULT_COLORS = { - bar: DEFAULT_CHART_COLORS, - line: DEFAULT_CHART_COLORS, - pie: DEFAULT_CHART_COLORS, - percentage: DEFAULT_CHART_COLORS, - heatmap: HEATMAP_COLORS_GREEN, - donut: DEFAULT_CHART_COLORS -}; - -// Universal constants -const ANGLE_RATIO = Math.PI / 180; -const FULL_ANGLE = 360; - -class SvgTip { - constructor({ - parent = null, - colors = [] - }) { - this.parent = parent; - this.colors = colors; - this.titleName = ''; - this.titleValue = ''; - this.listValues = []; - this.titleValueFirst = 0; - - this.x = 0; - this.y = 0; - - this.top = 0; - this.left = 0; - - this.setup(); - } - - setup() { - this.makeTooltip(); - } - - refresh() { - this.fill(); - this.calcPosition(); - } - - makeTooltip() { - this.container = $.create('div', { - inside: this.parent, - className: 'graph-svg-tip comparison', - innerHTML: ` -
    -
    ` - }); - this.hideTip(); - - this.title = this.container.querySelector('.title'); - this.dataPointList = this.container.querySelector('.data-point-list'); - - this.parent.addEventListener('mouseleave', () => { - this.hideTip(); - }); - } - - fill() { - let title; - if(this.index) { - this.container.setAttribute('data-point-index', this.index); - } - if(this.titleValueFirst) { - title = `${this.titleValue}${this.titleName}`; - } else { - title = `${this.titleName}${this.titleValue}`; - } - this.title.innerHTML = title; - this.dataPointList.innerHTML = ''; - - this.listValues.map((set, i) => { - const color = this.colors[i] || 'black'; - let value = set.formatted === 0 || set.formatted ? set.formatted : set.value; - - let li = $.create('li', { - styles: { - 'border-top': `3px solid ${color}` - }, - innerHTML: `${ value === 0 || value ? value : '' } - ${set.title ? set.title : '' }` - }); - - this.dataPointList.appendChild(li); - }); - } - - calcPosition() { - let width = this.container.offsetWidth; - - this.top = this.y - this.container.offsetHeight - - TOOLTIP_POINTER_TRIANGLE_HEIGHT; - this.left = this.x - width/2; - let maxLeft = this.parent.offsetWidth - width; - - let pointer = this.container.querySelector('.svg-pointer'); - - if(this.left < 0) { - pointer.style.left = `calc(50% - ${-1 * this.left}px)`; - this.left = 0; - } else if(this.left > maxLeft) { - let delta = this.left - maxLeft; - let pointerOffset = `calc(50% + ${delta}px)`; - pointer.style.left = pointerOffset; - - this.left = maxLeft; - } else { - pointer.style.left = `50%`; - } - } - - setValues(x, y, title = {}, listValues = [], index = -1) { - this.titleName = title.name; - this.titleValue = title.value; - this.listValues = listValues; - this.x = x; - this.y = y; - this.titleValueFirst = title.valueFirst || 0; - this.index = index; - this.refresh(); - } - - hideTip() { - this.container.style.top = '0px'; - this.container.style.left = '0px'; - this.container.style.opacity = '0'; - } - - showTip() { - this.container.style.top = this.top + 'px'; - this.container.style.left = this.left + 'px'; - this.container.style.opacity = '1'; - } -} - -/** - * Returns the value of a number upto 2 decimal places. - * @param {Number} d Any number - */ -function floatTwo(d) { - return parseFloat(d.toFixed(2)); -} - -/** - * Returns whether or not two given arrays are equal. - * @param {Array} arr1 First array - * @param {Array} arr2 Second array - */ - - -/** - * Shuffles array in place. ES6 version - * @param {Array} array An array containing the items. - */ - - -/** - * Fill an array with extra points - * @param {Array} array Array - * @param {Number} count number of filler elements - * @param {Object} element element to fill with - * @param {Boolean} start fill at start? - */ -function fillArray(array, count, element, start=false) { - if(!element) { - element = start ? array[0] : array[array.length - 1]; - } - let fillerArray = new Array(Math.abs(count)).fill(element); - array = start ? fillerArray.concat(array) : array.concat(fillerArray); - return array; -} - -/** - * Returns pixel width of string. - * @param {String} string - * @param {Number} charWidth Width of single char in pixels - */ -function getStringWidth(string, charWidth) { - return (string+"").length * charWidth; -} - - - -// https://stackoverflow.com/a/29325222 - - -function getPositionByAngle(angle, radius) { - return { - x: Math.sin(angle * ANGLE_RATIO) * radius, - y: Math.cos(angle * ANGLE_RATIO) * radius, - }; -} - -/** - * Check if a number is valid for svg attributes - * @param {object} candidate Candidate to test - * @param {Boolean} nonNegative flag to treat negative number as invalid - */ -function isValidNumber(candidate, nonNegative=false) { - if (Number.isNaN(candidate)) return false; - else if (candidate === undefined) return false; - else if (!Number.isFinite(candidate)) return false; - else if (nonNegative && candidate < 0) return false; - else return true; -} - -/** - * Round a number to the closes precision, max max precision 4 - * @param {Number} d Any Number - */ -function round(d) { - // https://floating-point-gui.de/ - // https://www.jacklmoore.com/notes/rounding-in-javascript/ - return Number(Math.round(d + 'e4') + 'e-4'); -} - -/** - * Creates a deep clone of an object - * @param {Object} candidate Any Object - */ - function deepClone(candidate) { - let cloned, value, key; - - if (candidate instanceof Date) { - return new Date(candidate.getTime()); - } - - if (typeof candidate !== "object" || candidate === null) { - return candidate; - } - - cloned = Array.isArray(candidate) ? [] : {}; - - for (key in candidate) { - value = candidate[key]; - - cloned[key] = deepClone(value); - } - - return cloned; - } - -function getBarHeightAndYAttr(yTop, zeroLine) { - let height, y; - if (yTop <= zeroLine) { - height = zeroLine - yTop; - y = yTop; - } else { - height = yTop - zeroLine; - y = zeroLine; - } - - return [height, y]; -} - -function equilizeNoOfElements(array1, array2, - extraCount = array2.length - array1.length) { - - // Doesn't work if either has zero elements. - if(extraCount > 0) { - array1 = fillArray(array1, extraCount); - } else { - array2 = fillArray(array2, extraCount); - } - return [array1, array2]; -} - -function truncateString(txt, len) { - if (!txt) { - return; - } - if (txt.length > len) { - return txt.slice(0, len-3) + '...'; - } else { - return txt; - } -} - -function shortenLargeNumber(label) { - let number; - if (typeof label === 'number') number = label; - else if (typeof label === 'string') { - number = Number(label); - if (Number.isNaN(number)) return label; - } - - // Using absolute since log wont work for negative numbers - let p = Math.floor(Math.log10(Math.abs(number))); - if (p <= 2) return number; // Return as is for a 3 digit number of less - let l = Math.floor(p / 3); - let shortened = (Math.pow(10, p - l * 3) * +(number / Math.pow(10, p)).toFixed(1)); - - // Correct for floating point error upto 2 decimal places - return Math.round(shortened*100)/100 + ' ' + ['', 'K', 'M', 'B', 'T'][l]; -} - -// cubic bezier curve calculation (from example by François Romain) -function getSplineCurvePointsStr(xList, yList) { - - let points=[]; - for(let i=0;i { - let lengthX = pointB[0] - pointA[0]; - let lengthY = pointB[1] - pointA[1]; - return { - length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)), - angle: Math.atan2(lengthY, lengthX) - }; - }; - - let controlPoint = (current, previous, next, reverse) => { - let p = previous || current; - let n = next || current; - let o = line(p, n); - let angle = o.angle + (reverse ? Math.PI : 0); - let length = o.length * smoothing; - let x = current[0] + Math.cos(angle) * length; - let y = current[1] + Math.sin(angle) * length; - return [x, y]; - }; - - let bezierCommand = (point, i, a) => { - let cps = controlPoint(a[i - 1], a[i - 2], point); - let cpe = controlPoint(point, a[i - 1], a[i + 1], true); - return `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`; - }; - - let pointStr = (points, command) => { - return points.reduce((acc, point, i, a) => i === 0 - ? `${point[0]},${point[1]}` - : `${acc} ${command(point, i, a)}`, ''); - }; - - return pointStr(points, bezierCommand); -} - -const PRESET_COLOR_MAP = { - 'light-blue': '#7cd6fd', - 'blue': '#5e64ff', - 'violet': '#743ee2', - 'red': '#ff5858', - 'orange': '#ffa00a', - 'yellow': '#feef72', - 'green': '#28a745', - 'light-green': '#98d85b', - 'purple': '#b554ff', - 'magenta': '#ffa3ef', - 'black': '#36114C', - 'grey': '#bdd3e6', - 'light-grey': '#f0f4f7', - 'dark-grey': '#b8c2cc' -}; - -function limitColor(r){ - if (r > 255) return 255; - else if (r < 0) return 0; - return r; -} - -function lightenDarkenColor(color, amt) { - let col = getColor(color); - let usePound = false; - if (col[0] == "#") { - col = col.slice(1); - usePound = true; - } - let num = parseInt(col,16); - let r = limitColor((num >> 16) + amt); - let b = limitColor(((num >> 8) & 0x00FF) + amt); - let g = limitColor((num & 0x0000FF) + amt); - return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16); -} - -function isValidColor(string) { - // https://stackoverflow.com/a/32685393 - let HEX_RE = /(^\s*)(#)((?:[A-Fa-f0-9]{3}){1,2})$/i; - let RGB_RE = /(^\s*)(rgb|hsl)(a?)[(]\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*(?:,\s*([\d.]+)\s*)?[)]$/i; - return HEX_RE.test(string) || RGB_RE.test(string); -} - -const getColor = (color) => { - // When RGB color, convert to hexadecimal (alpha value is omitted) - if((/rgb[a]{0,1}\([\d, ]+\)/gim).test(color)) { - return (/\D+(\d*)\D+(\d*)\D+(\d*)/gim).exec(color) - .map((x, i) => (i !== 0 ? Number(x).toString(16) : '#')) - .reduce((c, ch) => `${c}${ch}`); - } - return PRESET_COLOR_MAP[color] || color; -}; - -const AXIS_TICK_LENGTH = 6; -const LABEL_MARGIN = 4; -const LABEL_MAX_CHARS = 15; -const FONT_SIZE = 10; -const BASE_LINE_COLOR = '#dadada'; -const FONT_FILL = '#555b51'; - -function $$1(expr, con) { - return typeof expr === "string"? (con || document).querySelector(expr) : expr || null; -} - -function createSVG(tag, o) { - var element = document.createElementNS("http://www.w3.org/2000/svg", tag); - - for (var i in o) { - var val = o[i]; - - if (i === "inside") { - $$1(val).appendChild(element); - } - else if (i === "around") { - var ref = $$1(val); - ref.parentNode.insertBefore(element, ref); - element.appendChild(ref); - - } else if (i === "styles") { - if(typeof val === "object") { - Object.keys(val).map(prop => { - element.style[prop] = val[prop]; - }); - } - } else { - if(i === "className") { i = "class"; } - if(i === "innerHTML") { - element['textContent'] = val; - } else { - element.setAttribute(i, val); - } - } - } - - return element; -} - -function renderVerticalGradient(svgDefElem, gradientId) { - return createSVG('linearGradient', { - inside: svgDefElem, - id: gradientId, - x1: 0, - x2: 0, - y1: 0, - y2: 1 - }); -} - -function setGradientStop(gradElem, offset, color, opacity) { - return createSVG('stop', { - 'inside': gradElem, - 'style': `stop-color: ${color}`, - 'offset': offset, - 'stop-opacity': opacity - }); -} - -function makeSVGContainer(parent, className, width, height) { - return createSVG('svg', { - className: className, - inside: parent, - width: width, - height: height - }); -} - -function makeSVGDefs(svgContainer) { - return createSVG('defs', { - inside: svgContainer, - }); -} - -function makeSVGGroup(className, transform='', parent=undefined) { - let args = { - className: className, - transform: transform - }; - if(parent) args.inside = parent; - return createSVG('g', args); -} - - - -function makePath(pathStr, className='', stroke='none', fill='none', strokeWidth=2) { - return createSVG('path', { - className: className, - d: pathStr, - styles: { - stroke: stroke, - fill: fill, - 'stroke-width': strokeWidth - } - }); -} - -function makeArcPathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ - let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; - let [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y]; - return `M${center.x} ${center.y} - L${arcStartX} ${arcStartY} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${arcEndY} z`; -} - -function makeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ - let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; - let [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, center.y * 2, center.y + endPosition.y]; - return `M${center.x} ${center.y} - L${arcStartX} ${arcStartY} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${midArc} z - L${arcStartX} ${midArc} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${arcEndY} z`; -} - -function makeArcStrokePathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ - let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; - let [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y]; - - return `M${arcStartX} ${arcStartY} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${arcEndY}`; -} - -function makeStrokeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ - let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; - let [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, radius * 2 + arcStartY, center.y + startPosition.y]; - - return `M${arcStartX} ${arcStartY} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${midArc} - M${arcStartX} ${midArc} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${arcEndY}`; -} - -function makeGradient(svgDefElem, color, lighter = false) { - let gradientId ='path-fill-gradient' + '-' + color + '-' +(lighter ? 'lighter' : 'default'); - let gradientDef = renderVerticalGradient(svgDefElem, gradientId); - let opacities = [1, 0.6, 0.2]; - if(lighter) { - opacities = [0.4, 0.2, 0]; - } - - setGradientStop(gradientDef, "0%", color, opacities[0]); - setGradientStop(gradientDef, "50%", color, opacities[1]); - setGradientStop(gradientDef, "100%", color, opacities[2]); - - return gradientId; -} - -function percentageBar(x, y, width, height, - depth=PERCENTAGE_BAR_DEFAULT_DEPTH, fill='none') { - - let args = { - className: 'percentage-bar', - x: x, - y: y, - width: width, - height: height, - fill: fill, - styles: { - 'stroke': lightenDarkenColor(fill, -25), - // Diabolically good: https://stackoverflow.com/a/9000859 - // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray - 'stroke-dasharray': `0, ${height + width}, ${width}, ${height}`, - 'stroke-width': depth - }, - }; - - return createSVG("rect", args); -} - -function heatSquare(className, x, y, size, radius, fill='none', data={}) { - let args = { - className: className, - x: x, - y: y, - width: size, - height: size, - rx: radius, - fill: fill - }; - - Object.keys(data).map(key => { - args[key] = data[key]; - }); - - return createSVG("rect", args); -} - -function legendBar(x, y, size, fill='none', label, truncate=false) { - label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label; - - let args = { - className: 'legend-bar', - x: 0, - y: 0, - width: size, - height: '2px', - fill: fill - }; - let text = createSVG('text', { - className: 'legend-dataset-text', - x: 0, - y: 0, - dy: (FONT_SIZE * 2) + 'px', - 'font-size': (FONT_SIZE * 1.2) + 'px', - 'text-anchor': 'start', - fill: FONT_FILL, - innerHTML: label - }); - - let group = createSVG('g', { - transform: `translate(${x}, ${y})` - }); - group.appendChild(createSVG("rect", args)); - group.appendChild(text); - - return group; -} - -function legendDot(x, y, size, fill='none', label, truncate=false) { - label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label; - - let args = { - className: 'legend-dot', - cx: 0, - cy: 0, - r: size, - fill: fill - }; - let text = createSVG('text', { - className: 'legend-dataset-text', - x: 0, - y: 0, - dx: (FONT_SIZE) + 'px', - dy: (FONT_SIZE/3) + 'px', - 'font-size': (FONT_SIZE * 1.2) + 'px', - 'text-anchor': 'start', - fill: FONT_FILL, - innerHTML: label - }); - - let group = createSVG('g', { - transform: `translate(${x}, ${y})` - }); - group.appendChild(createSVG("circle", args)); - group.appendChild(text); - - return group; -} - -function makeText(className, x, y, content, options = {}) { - let fontSize = options.fontSize || FONT_SIZE; - let dy = options.dy !== undefined ? options.dy : (fontSize / 2); - let fill = options.fill || FONT_FILL; - let textAnchor = options.textAnchor || 'start'; - return createSVG('text', { - className: className, - x: x, - y: y, - dy: dy + 'px', - 'font-size': fontSize + 'px', - fill: fill, - 'text-anchor': textAnchor, - innerHTML: content - }); -} - -function makeVertLine(x, label, y1, y2, options={}) { - if(!options.stroke) options.stroke = BASE_LINE_COLOR; - let l = createSVG('line', { - className: 'line-vertical ' + options.className, - x1: 0, - x2: 0, - y1: y1, - y2: y2, - styles: { - stroke: options.stroke - } - }); - - let text = createSVG('text', { - x: 0, - y: y1 > y2 ? y1 + LABEL_MARGIN : y1 - LABEL_MARGIN - FONT_SIZE, - dy: FONT_SIZE + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': 'middle', - innerHTML: label + "" - }); - - let line = createSVG('g', { - transform: `translate(${ x }, 0)` - }); - - line.appendChild(l); - line.appendChild(text); - - return line; -} - -function makeHoriLine(y, label, x1, x2, options={}) { - if(!options.stroke) options.stroke = BASE_LINE_COLOR; - if(!options.lineType) options.lineType = ''; - if (options.shortenNumbers) label = shortenLargeNumber(label); - - let className = 'line-horizontal ' + options.className + - (options.lineType === "dashed" ? "dashed": ""); - - let l = createSVG('line', { - className: className, - x1: x1, - x2: x2, - y1: 0, - y2: 0, - styles: { - stroke: options.stroke - } - }); - - let text = createSVG('text', { - x: x1 < x2 ? x1 - LABEL_MARGIN : x1 + LABEL_MARGIN, - y: 0, - dy: (FONT_SIZE / 2 - 2) + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': x1 < x2 ? 'end' : 'start', - innerHTML: label+"" - }); - - let line = createSVG('g', { - transform: `translate(0, ${y})`, - 'stroke-opacity': 1 - }); - - if(text === 0 || text === '0') { - line.style.stroke = "rgba(27, 31, 35, 0.6)"; - } - - line.appendChild(l); - line.appendChild(text); - - return line; -} - -function yLine(y, label, width, options={}) { - if (!isValidNumber(y)) y = 0; - - if(!options.pos) options.pos = 'left'; - if(!options.offset) options.offset = 0; - if(!options.mode) options.mode = 'span'; - if(!options.stroke) options.stroke = BASE_LINE_COLOR; - if(!options.className) options.className = ''; - - let x1 = -1 * AXIS_TICK_LENGTH; - let x2 = options.mode === 'span' ? width + AXIS_TICK_LENGTH : 0; - - if(options.mode === 'tick' && options.pos === 'right') { - x1 = width + AXIS_TICK_LENGTH; - x2 = width; - } - - // let offset = options.pos === 'left' ? -1 * options.offset : options.offset; - - x1 += options.offset; - x2 += options.offset; - - return makeHoriLine(y, label, x1, x2, { - stroke: options.stroke, - className: options.className, - lineType: options.lineType, - shortenNumbers: options.shortenNumbers - }); -} - -function xLine(x, label, height, options={}) { - if (!isValidNumber(x)) x = 0; - - if(!options.pos) options.pos = 'bottom'; - if(!options.offset) options.offset = 0; - if(!options.mode) options.mode = 'span'; - if(!options.stroke) options.stroke = BASE_LINE_COLOR; - if(!options.className) options.className = ''; - - // Draw X axis line in span/tick mode with optional label - // y2(span) - // | - // | - // x line | - // | - // | - // ---------------------+-- y2(tick) - // | - // y1 - - let y1 = height + AXIS_TICK_LENGTH; - let y2 = options.mode === 'span' ? -1 * AXIS_TICK_LENGTH : height; - - if(options.mode === 'tick' && options.pos === 'top') { - // top axis ticks - y1 = -1 * AXIS_TICK_LENGTH; - y2 = 0; - } - - return makeVertLine(x, label, y1, y2, { - stroke: options.stroke, - className: options.className, - lineType: options.lineType - }); -} - -function yMarker(y, label, width, options={}) { - if(!options.labelPos) options.labelPos = 'right'; - let x = options.labelPos === 'left' ? LABEL_MARGIN - : width - getStringWidth(label, 5) - LABEL_MARGIN; - - let labelSvg = createSVG('text', { - className: 'chart-label', - x: x, - y: 0, - dy: (FONT_SIZE / -2) + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': 'start', - innerHTML: label+"" - }); - - let line = makeHoriLine(y, '', 0, width, { - stroke: options.stroke || BASE_LINE_COLOR, - className: options.className || '', - lineType: options.lineType - }); - - line.appendChild(labelSvg); - - return line; -} - -function yRegion(y1, y2, width, label, options={}) { - // return a group - let height = y1 - y2; - - let rect = createSVG('rect', { - className: `bar mini`, // remove class - styles: { - fill: `rgba(228, 234, 239, 0.49)`, - stroke: BASE_LINE_COLOR, - 'stroke-dasharray': `${width}, ${height}` - }, - // 'data-point-index': index, - x: 0, - y: 0, - width: width, - height: height - }); - - if(!options.labelPos) options.labelPos = 'right'; - let x = options.labelPos === 'left' ? LABEL_MARGIN - : width - getStringWidth(label+"", 4.5) - LABEL_MARGIN; - - let labelSvg = createSVG('text', { - className: 'chart-label', - x: x, - y: 0, - dy: (FONT_SIZE / -2) + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': 'start', - innerHTML: label+"" - }); - - let region = createSVG('g', { - transform: `translate(0, ${y2})` - }); - - region.appendChild(rect); - region.appendChild(labelSvg); - - return region; -} - -function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) { - let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine); - y -= offset; - - if(height === 0) { - height = meta.minHeight; - y -= meta.minHeight; - } - - // Preprocess numbers to avoid svg building errors - if (!isValidNumber(x)) x = 0; - if (!isValidNumber(y)) y = 0; - if (!isValidNumber(height, true)) height = 0; - if (!isValidNumber(width, true)) width = 0; - - let rect = createSVG('rect', { - className: `bar mini`, - style: `fill: ${color}`, - 'data-point-index': index, - x: x, - y: y, - width: width, - height: height - }); - - label += ""; - - if(!label && !label.length) { - return rect; - } else { - rect.setAttribute('y', 0); - rect.setAttribute('x', 0); - let text = createSVG('text', { - className: 'data-point-value', - x: width/2, - y: 0, - dy: (FONT_SIZE / 2 * -1) + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': 'middle', - innerHTML: label - }); - - let group = createSVG('g', { - 'data-point-index': index, - transform: `translate(${x}, ${y})` - }); - group.appendChild(rect); - group.appendChild(text); - - return group; - } -} - -function datasetDot(x, y, radius, color, label='', index=0) { - let dot = createSVG('circle', { - style: `fill: ${color}`, - 'data-point-index': index, - cx: x, - cy: y, - r: radius - }); - - label += ""; - - if(!label && !label.length) { - return dot; - } else { - dot.setAttribute('cy', 0); - dot.setAttribute('cx', 0); - - let text = createSVG('text', { - className: 'data-point-value', - x: 0, - y: 0, - dy: (FONT_SIZE / 2 * -1 - radius) + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': 'middle', - innerHTML: label - }); - - let group = createSVG('g', { - 'data-point-index': index, - transform: `translate(${x}, ${y})` - }); - group.appendChild(dot); - group.appendChild(text); - - return group; - } -} - -function getPaths(xList, yList, color, options={}, meta={}) { - let pointsList = yList.map((y, i) => (xList[i] + ',' + y)); - let pointsStr = pointsList.join("L"); - - // Spline - if (options.spline) - pointsStr = getSplineCurvePointsStr(xList, yList); - - let path = makePath("M"+pointsStr, 'line-graph-path', color); - - // HeatLine - if(options.heatline) { - let gradient_id = makeGradient(meta.svgDefs, color); - path.style.stroke = `url(#${gradient_id})`; - } - - let paths = { - path: path - }; - - // Region - if(options.regionFill) { - let gradient_id_region = makeGradient(meta.svgDefs, color, true); - - let pathStr = "M" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`; - paths.region = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`); - } - - return paths; -} - -let makeOverlay = { - 'bar': (unit) => { - let transformValue; - if(unit.nodeName !== 'rect') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let overlay = unit.cloneNode(); - overlay.style.fill = '#000000'; - overlay.style.opacity = '0.4'; - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - return overlay; - }, - - 'dot': (unit) => { - let transformValue; - if(unit.nodeName !== 'circle') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let overlay = unit.cloneNode(); - let radius = unit.getAttribute('r'); - let fill = unit.getAttribute('fill'); - overlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR); - overlay.setAttribute('fill', fill); - overlay.style.opacity = '0.6'; - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - return overlay; - }, - - 'heat_square': (unit) => { - let transformValue; - if(unit.nodeName !== 'circle') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let overlay = unit.cloneNode(); - let radius = unit.getAttribute('r'); - let fill = unit.getAttribute('fill'); - overlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR); - overlay.setAttribute('fill', fill); - overlay.style.opacity = '0.6'; - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - return overlay; - } -}; - -let updateOverlay = { - 'bar': (unit, overlay) => { - let transformValue; - if(unit.nodeName !== 'rect') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let attributes = ['x', 'y', 'width', 'height']; - Object.values(unit.attributes) - .filter(attr => attributes.includes(attr.name) && attr.specified) - .map(attr => { - overlay.setAttribute(attr.name, attr.nodeValue); - }); - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - }, - - 'dot': (unit, overlay) => { - let transformValue; - if(unit.nodeName !== 'circle') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let attributes = ['cx', 'cy']; - Object.values(unit.attributes) - .filter(attr => attributes.includes(attr.name) && attr.specified) - .map(attr => { - overlay.setAttribute(attr.name, attr.nodeValue); - }); - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - }, - - 'heat_square': (unit, overlay) => { - let transformValue; - if(unit.nodeName !== 'circle') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let attributes = ['cx', 'cy']; - Object.values(unit.attributes) - .filter(attr => attributes.includes(attr.name) && attr.specified) - .map(attr => { - overlay.setAttribute(attr.name, attr.nodeValue); - }); - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - }, -}; - -const UNIT_ANIM_DUR = 350; -const PATH_ANIM_DUR = 350; -const MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR; -const REPLACE_ALL_NEW_DUR = 250; - -const STD_EASING = 'easein'; - -function translate(unit, oldCoord, newCoord, duration) { - let old = typeof oldCoord === 'string' ? oldCoord : oldCoord.join(', '); - return [ - unit, - {transform: newCoord.join(', ')}, - duration, - STD_EASING, - "translate", - {transform: old} - ]; -} - -function translateVertLine(xLine, newX, oldX) { - return translate(xLine, [oldX, 0], [newX, 0], MARKER_LINE_ANIM_DUR); -} - -function translateHoriLine(yLine, newY, oldY) { - return translate(yLine, [0, oldY], [0, newY], MARKER_LINE_ANIM_DUR); -} - -function animateRegion(rectGroup, newY1, newY2, oldY2) { - let newHeight = newY1 - newY2; - let rect = rectGroup.childNodes[0]; - let width = rect.getAttribute("width"); - let rectAnim = [ - rect, - { height: newHeight, 'stroke-dasharray': `${width}, ${newHeight}` }, - MARKER_LINE_ANIM_DUR, - STD_EASING - ]; - - let groupAnim = translate(rectGroup, [0, oldY2], [0, newY2], MARKER_LINE_ANIM_DUR); - return [rectAnim, groupAnim]; -} - -function animateBar(bar, x, yTop, width, offset=0, meta={}) { - let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine); - y -= offset; - if(bar.nodeName !== 'rect') { - let rect = bar.childNodes[0]; - let rectAnim = [ - rect, - {width: width, height: height}, - UNIT_ANIM_DUR, - STD_EASING - ]; - - let oldCoordStr = bar.getAttribute("transform").split("(")[1].slice(0, -1); - let groupAnim = translate(bar, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR); - return [rectAnim, groupAnim]; - } else { - return [[bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]]; - } - // bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein); -} - -function animateDot(dot, x, y) { - if(dot.nodeName !== 'circle') { - let oldCoordStr = dot.getAttribute("transform").split("(")[1].slice(0, -1); - let groupAnim = translate(dot, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR); - return [groupAnim]; - } else { - return [[dot, {cx: x, cy: y}, UNIT_ANIM_DUR, STD_EASING]]; - } - // dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein); -} - -function animatePath(paths, newXList, newYList, zeroLine, spline) { - let pathComponents = []; - let pointsStr = newYList.map((y, i) => (newXList[i] + ',' + y)).join("L"); - - if (spline) - pointsStr = getSplineCurvePointsStr(newXList, newYList); - - const animPath = [paths.path, {d:"M" + pointsStr}, PATH_ANIM_DUR, STD_EASING]; - pathComponents.push(animPath); - - if(paths.region) { - let regStartPt = `${newXList[0]},${zeroLine}L`; - let regEndPt = `L${newXList.slice(-1)[0]}, ${zeroLine}`; - - const animRegion = [ - paths.region, - {d:"M" + regStartPt + pointsStr + regEndPt}, - PATH_ANIM_DUR, - STD_EASING - ]; - pathComponents.push(animRegion); - } - - return pathComponents; -} - -function animatePathStr(oldPath, pathStr) { - return [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING]; -} - -// Leveraging SMIL Animations - -const EASING = { - ease: "0.25 0.1 0.25 1", - linear: "0 0 1 1", - // easein: "0.42 0 1 1", - easein: "0.1 0.8 0.2 1", - easeout: "0 0 0.58 1", - easeinout: "0.42 0 0.58 1" -}; - -function animateSVGElement(element, props, dur, easingType="linear", type=undefined, oldValues={}) { - - let animElement = element.cloneNode(true); - let newElement = element.cloneNode(true); - - for(var attributeName in props) { - let animateElement; - if(attributeName === 'transform') { - animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform"); - } else { - animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animate"); - } - let currentValue = oldValues[attributeName] || element.getAttribute(attributeName); - let value = props[attributeName]; - - let animAttr = { - attributeName: attributeName, - from: currentValue, - to: value, - begin: "0s", - dur: dur/1000 + "s", - values: currentValue + ";" + value, - keySplines: EASING[easingType], - keyTimes: "0;1", - calcMode: "spline", - fill: 'freeze' - }; - - if(type) { - animAttr["type"] = type; - } - - for (var i in animAttr) { - animateElement.setAttribute(i, animAttr[i]); - } - - animElement.appendChild(animateElement); - - if(type) { - newElement.setAttribute(attributeName, `translate(${value})`); - } else { - newElement.setAttribute(attributeName, value); - } - } - - return [animElement, newElement]; -} - -function transform(element, style) { // eslint-disable-line no-unused-vars - element.style.transform = style; - element.style.webkitTransform = style; - element.style.msTransform = style; - element.style.mozTransform = style; - element.style.oTransform = style; -} - -function animateSVG(svgContainer, elements) { - let newElements = []; - let animElements = []; - - elements.map(element => { - let unit = element[0]; - let parent = unit.parentNode; - - let animElement, newElement; - - element[0] = unit; - [animElement, newElement] = animateSVGElement(...element); - - newElements.push(newElement); - animElements.push([animElement, parent]); - - if (parent) { - parent.replaceChild(animElement, unit); - } - }); - - let animSvg = svgContainer.cloneNode(true); - - animElements.map((animElement, i) => { - if (animElement[1]) { - animElement[1].replaceChild(newElements[i], animElement[0]); - elements[i][0] = newElements[i]; - } - }); - - return animSvg; -} - -function runSMILAnimation(parent, svgElement, elementsToAnimate) { - if(elementsToAnimate.length === 0) return; - - let animSvgElement = animateSVG(svgElement, elementsToAnimate); - if(svgElement.parentNode == parent) { - parent.removeChild(svgElement); - parent.appendChild(animSvgElement); - - } - - // Replace the new svgElement (data has already been replaced) - setTimeout(() => { - if(animSvgElement.parentNode == parent) { - parent.removeChild(animSvgElement); - parent.appendChild(svgElement); - } - }, REPLACE_ALL_NEW_DUR); -} - -const CSSTEXT = ".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}"; - -function downloadFile(filename, data) { - var a = document.createElement('a'); - a.style = "display: none"; - var blob = new Blob(data, {type: "image/svg+xml; charset=utf-8"}); - var url = window.URL.createObjectURL(blob); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - setTimeout(function(){ - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 300); -} - -function prepareForExport(svg) { - let clone = svg.cloneNode(true); - clone.classList.add('chart-container'); - clone.setAttribute('xmlns', "http://www.w3.org/2000/svg"); - clone.setAttribute('xmlns:xlink', "http://www.w3.org/1999/xlink"); - let styleEl = $.create('style', { - 'innerHTML': CSSTEXT - }); - clone.insertBefore(styleEl, clone.firstChild); - - let container = $.create('div'); - container.appendChild(clone); - - return container.innerHTML; -} - -class BaseChart { - constructor(parent, options) { - // deepclone options to avoid making changes to orignal object - options = deepClone(options); - - this.parent = typeof parent === 'string' - ? document.querySelector(parent) - : parent; - - if (!(this.parent instanceof HTMLElement)) { - throw new Error('No `parent` element to render on was provided.'); - } - - this.rawChartArgs = options; - - this.title = options.title || ''; - this.type = options.type || ''; - - this.realData = this.prepareData(options.data); - this.data = this.prepareFirstData(this.realData); - - this.colors = this.validateColors(options.colors, this.type); - - this.config = { - showTooltip: 1, // calculate - showLegend: 1, // calculate - isNavigable: options.isNavigable || 0, - animate: (typeof options.animate !== 'undefined') ? options.animate : 1, - truncateLegends: options.truncateLegends || 1 - }; - - this.measures = JSON.parse(JSON.stringify(BASE_MEASURES)); - let m = this.measures; - this.setMeasures(options); - if(!this.title.length) { m.titleHeight = 0; } - if(!this.config.showLegend) m.legendHeight = 0; - this.argHeight = options.height || m.baseHeight; - - this.state = {}; - this.options = {}; - - this.initTimeout = INIT_CHART_UPDATE_TIMEOUT; - - if(this.config.isNavigable) { - this.overlays = []; - } - - this.configure(options); - } - - prepareData(data) { - return data; - } - - prepareFirstData(data) { - return data; - } - - validateColors(colors, type) { - const validColors = []; - colors = (colors || []).concat(DEFAULT_COLORS[type]); - colors.forEach((string) => { - const color = getColor(string); - if(!isValidColor(color)) { - console.warn('"' + string + '" is not a valid color.'); - } else { - validColors.push(color); - } - }); - return validColors; - } - - setMeasures() { - // Override measures, including those for title and legend - // set config for legend and title - } - - configure() { - let height = this.argHeight; - this.baseHeight = height; - this.height = height - getExtraHeight(this.measures); - - // Bind window events - this.boundDrawFn = () => this.draw(true); - if (ResizeObserver) { - this.resizeObserver = new ResizeObserver(this.boundDrawFn); - this.resizeObserver.observe(this.parent); - } - window.addEventListener('resize', this.boundDrawFn); - window.addEventListener('orientationchange', this.boundDrawFn); - } - - destroy() { - if (this.resizeObserver) this.resizeObserver.disconnect(); - window.removeEventListener('resize', this.boundDrawFn); - window.removeEventListener('orientationchange', this.boundDrawFn); - } - - // Has to be called manually - setup() { - this.makeContainer(); - this.updateWidth(); - this.makeTooltip(); - - this.draw(false, true); - } - - makeContainer() { - // Chart needs a dedicated parent element - this.parent.innerHTML = ''; - - let args = { - inside: this.parent, - className: 'chart-container' - }; - - if(this.independentWidth) { - args.styles = { width: this.independentWidth + 'px' }; - } - - this.container = $.create('div', args); - } - - makeTooltip() { - this.tip = new SvgTip({ - parent: this.container, - colors: this.colors - }); - this.bindTooltip(); - } - - bindTooltip() {} - - draw(onlyWidthChange=false, init=false) { - if (onlyWidthChange && isHidden(this.parent)) { - // Don't update anything if the chart is hidden - return; - } - this.updateWidth(); - - this.calc(onlyWidthChange); - this.makeChartArea(); - this.setupComponents(); - - this.components.forEach(c => c.setup(this.drawArea)); - // this.components.forEach(c => c.make()); - this.render(this.components, false); - - if(init) { - this.data = this.realData; - setTimeout(() => {this.update(this.data);}, this.initTimeout); - } - - this.renderLegend(); - - this.setupNavigation(init); - } - - calc() {} // builds state - - updateWidth() { - this.baseWidth = getElementContentWidth(this.parent); - this.width = this.baseWidth - getExtraWidth(this.measures); - } - - makeChartArea() { - if(this.svg) { - this.container.removeChild(this.svg); - } - let m = this.measures; - - this.svg = makeSVGContainer( - this.container, - 'frappe-chart chart', - this.baseWidth, - this.baseHeight - ); - this.svgDefs = makeSVGDefs(this.svg); - - if(this.title.length) { - this.titleEL = makeText( - 'title', - m.margins.left, - m.margins.top, - this.title, - { - fontSize: m.titleFontSize, - fill: '#666666', - dy: m.titleFontSize - } - ); - } - - let top = getTopOffset(m); - this.drawArea = makeSVGGroup( - this.type + '-chart chart-draw-area', - `translate(${getLeftOffset(m)}, ${top})` - ); - - if(this.config.showLegend) { - top += this.height + m.paddings.bottom; - this.legendArea = makeSVGGroup( - 'chart-legend', - `translate(${getLeftOffset(m)}, ${top})` - ); - } - - if(this.title.length) { this.svg.appendChild(this.titleEL); } - this.svg.appendChild(this.drawArea); - if(this.config.showLegend) { this.svg.appendChild(this.legendArea); } - - this.updateTipOffset(getLeftOffset(m), getTopOffset(m)); - } - - updateTipOffset(x, y) { - this.tip.offset = { - x: x, - y: y - }; - } - - setupComponents() { this.components = new Map(); } - - update(data) { - if(!data) { - console.error('No data to update.'); - } - this.data = this.prepareData(data); - this.calc(); // builds state - this.render(this.components, this.config.animate); - this.renderLegend(); - } - - render(components=this.components, animate=true) { - if(this.config.isNavigable) { - // Remove all existing overlays - this.overlays.map(o => o.parentNode.removeChild(o)); - // ref.parentNode.insertBefore(element, ref); - } - let elementsToAnimate = []; - // Can decouple to this.refreshComponents() first to save animation timeout - components.forEach(c => { - elementsToAnimate = elementsToAnimate.concat(c.update(animate)); - }); - if(elementsToAnimate.length > 0) { - runSMILAnimation(this.container, this.svg, elementsToAnimate); - setTimeout(() => { - components.forEach(c => c.make()); - this.updateNav(); - }, CHART_POST_ANIMATE_TIMEOUT); - } else { - components.forEach(c => c.make()); - this.updateNav(); - } - } - - updateNav() { - if(this.config.isNavigable) { - this.makeOverlay(); - this.bindUnits(); - } - } - - renderLegend() {} - - setupNavigation(init=false) { - if(!this.config.isNavigable) return; - - if(init) { - this.bindOverlay(); - - this.keyActions = { - '13': this.onEnterKey.bind(this), - '37': this.onLeftArrow.bind(this), - '38': this.onUpArrow.bind(this), - '39': this.onRightArrow.bind(this), - '40': this.onDownArrow.bind(this), - }; - - document.addEventListener('keydown', (e) => { - if(isElementInViewport(this.container)) { - e = e || window.event; - if(this.keyActions[e.keyCode]) { - this.keyActions[e.keyCode](); - } - } - }); - } - } - - makeOverlay() {} - updateOverlay() {} - bindOverlay() {} - bindUnits() {} - - onLeftArrow() {} - onRightArrow() {} - onUpArrow() {} - onDownArrow() {} - onEnterKey() {} - - addDataPoint() {} - removeDataPoint() {} - - getDataPoint() {} - setCurrentDataPoint() {} - - updateDataset() {} - - export() { - let chartSvg = prepareForExport(this.svg); - downloadFile(this.title || 'Chart', [chartSvg]); - } -} - -class AggregationChart extends BaseChart { - constructor(parent, args) { - super(parent, args); - } - - configure(args) { - super.configure(args); - - this.config.formatTooltipY = (args.tooltipOptions || {}).formatTooltipY; - this.config.maxSlices = args.maxSlices || 20; - this.config.maxLegendPoints = args.maxLegendPoints || 20; - } - - calc() { - let s = this.state; - let maxSlices = this.config.maxSlices; - s.sliceTotals = []; - - let allTotals = this.data.labels.map((label, i) => { - let total = 0; - this.data.datasets.map(e => { - total += e.values[i]; - }); - return [total, label]; - }).filter(d => { return d[0] >= 0; }); // keep only positive results - - let totals = allTotals; - if(allTotals.length > maxSlices) { - // Prune and keep a grey area for rest as per maxSlices - allTotals.sort((a, b) => { return b[0] - a[0]; }); - - totals = allTotals.slice(0, maxSlices-1); - let remaining = allTotals.slice(maxSlices-1); - - let sumOfRemaining = 0; - remaining.map(d => {sumOfRemaining += d[0];}); - totals.push([sumOfRemaining, 'Rest']); - this.colors[maxSlices-1] = 'grey'; - } - - s.labels = []; - totals.map(d => { - s.sliceTotals.push(round(d[0])); - s.labels.push(d[1]); - }); - - s.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0); - - this.center = { - x: this.width / 2, - y: this.height / 2 - }; - } - - renderLegend() { - let s = this.state; - this.legendArea.textContent = ''; - this.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints); - - let count = 0; - let y = 0; - this.legendTotals.map((d, i) => { - let barWidth = 150; - let divisor = Math.floor( - (this.width - getExtraWidth(this.measures))/barWidth - ); - if (this.legendTotals.length < divisor) { - barWidth = this.width/this.legendTotals.length; - } - if(count > divisor) { - count = 0; - y += 20; - } - let x = barWidth * count + 5; - let label = this.config.truncateLegends ? truncateString(s.labels[i], barWidth/10) : s.labels[i]; - let formatted = this.config.formatTooltipY ? this.config.formatTooltipY(d) : d; - let dot = legendDot( - x, - y, - 5, - this.colors[i], - `${label}: ${formatted}`, - false - ); - this.legendArea.appendChild(dot); - count++; - }); - } -} - -// Playing around with dates - -const NO_OF_YEAR_MONTHS = 12; -const NO_OF_DAYS_IN_WEEK = 7; - -const NO_OF_MILLIS = 1000; -const SEC_IN_DAY = 86400; - -const MONTH_NAMES = ["January", "February", "March", "April", "May", - "June", "July", "August", "September", "October", "November", "December"]; - - -const DAY_NAMES_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; - - -// https://stackoverflow.com/a/11252167/6495043 -function treatAsUtc(date) { - let result = new Date(date); - result.setMinutes(result.getMinutes() - result.getTimezoneOffset()); - return result; -} - -function getYyyyMmDd(date) { - let dd = date.getDate(); - let mm = date.getMonth() + 1; // getMonth() is zero-based - return [ - date.getFullYear(), - (mm>9 ? '' : '0') + mm, - (dd>9 ? '' : '0') + dd - ].join('-'); -} - -function clone(date) { - return new Date(date.getTime()); -} - - - - - -// export function getMonthsBetween(startDate, endDate) {} - -function getWeeksBetween(startDate, endDate) { - let weekStartDate = setDayToSunday(startDate); - return Math.ceil(getDaysBetween(weekStartDate, endDate) / NO_OF_DAYS_IN_WEEK); -} - -function getDaysBetween(startDate, endDate) { - let millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS; - return (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay; -} - -function areInSameMonth(startDate, endDate) { - return startDate.getMonth() === endDate.getMonth() - && startDate.getFullYear() === endDate.getFullYear(); -} - -function getMonthName(i, short=false) { - let monthName = MONTH_NAMES[i]; - return short ? monthName.slice(0, 3) : monthName; -} - -function getLastDateInMonth (month, year) { - return new Date(year, month + 1, 0); // 0: last day in previous month -} - -// mutates -function setDayToSunday(date) { - let newDate = clone(date); - const day = newDate.getDay(); - if(day !== 0) { - addDays(newDate, (-1) * day); - } - return newDate; -} - -// mutates -function addDays(date, numberOfDays) { - date.setDate(date.getDate() + numberOfDays); -} - -class ChartComponent { - constructor({ - layerClass = '', - layerTransform = '', - constants, - - getData, - makeElements, - animateElements - }) { - this.layerTransform = layerTransform; - this.constants = constants; - - this.makeElements = makeElements; - this.getData = getData; - - this.animateElements = animateElements; - - this.store = []; - this.labels = []; - - this.layerClass = layerClass; - this.layerClass = typeof(this.layerClass) === 'function' - ? this.layerClass() : this.layerClass; - - this.refresh(); - } - - refresh(data) { - this.data = data || this.getData(); - } - - setup(parent) { - this.layer = makeSVGGroup(this.layerClass, this.layerTransform, parent); - } - - make() { - this.render(this.data); - this.oldData = this.data; - } - - render(data) { - this.store = this.makeElements(data); - - this.layer.textContent = ''; - this.store.forEach(element => { - this.layer.appendChild(element); - }); - this.labels.forEach(element => { - this.layer.appendChild(element); - }); - } - - update(animate = true) { - this.refresh(); - let animateElements = []; - if(animate) { - animateElements = this.animateElements(this.data) || []; - } - return animateElements; - } -} - -let componentConfigs = { - donutSlices: { - layerClass: 'donut-slices', - makeElements(data) { - return data.sliceStrings.map((s, i) => { - let slice = makePath(s, 'donut-path', data.colors[i], 'none', data.strokeWidth); - slice.style.transition = 'transform .3s;'; - return slice; - }); - }, - - animateElements(newData) { - return this.store.map((slice, i) => animatePathStr(slice, newData.sliceStrings[i])); - }, - }, - pieSlices: { - layerClass: 'pie-slices', - makeElements(data) { - return data.sliceStrings.map((s, i) =>{ - let slice = makePath(s, 'pie-path', 'none', data.colors[i]); - slice.style.transition = 'transform .3s;'; - return slice; - }); - }, - - animateElements(newData) { - return this.store.map((slice, i) => - animatePathStr(slice, newData.sliceStrings[i]) - ); - } - }, - percentageBars: { - layerClass: 'percentage-bars', - makeElements(data) { - return data.xPositions.map((x, i) =>{ - let y = 0; - let bar = percentageBar(x, y, data.widths[i], - this.constants.barHeight, this.constants.barDepth, data.colors[i]); - return bar; - }); - }, - - animateElements(newData) { - if(newData) return []; - } - }, - yAxis: { - layerClass: 'y axis', - makeElements(data) { - return data.positions.map((position, i) => - yLine(position, data.labels[i], this.constants.width, - {mode: this.constants.mode, pos: this.constants.pos, shortenNumbers: this.constants.shortenNumbers}) - ); - }, - - animateElements(newData) { - let newPos = newData.positions; - let newLabels = newData.labels; - let oldPos = this.oldData.positions; - let oldLabels = this.oldData.labels; - - [oldPos, newPos] = equilizeNoOfElements(oldPos, newPos); - [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels); - - this.render({ - positions: oldPos, - labels: newLabels - }); - - return this.store.map((line, i) => { - return translateHoriLine( - line, newPos[i], oldPos[i] - ); - }); - } - }, - - xAxis: { - layerClass: 'x axis', - makeElements(data) { - return data.positions.map((position, i) => - xLine(position, data.calcLabels[i], this.constants.height, - {mode: this.constants.mode, pos: this.constants.pos}) - ); - }, - - animateElements(newData) { - let newPos = newData.positions; - let newLabels = newData.calcLabels; - let oldPos = this.oldData.positions; - let oldLabels = this.oldData.calcLabels; - - [oldPos, newPos] = equilizeNoOfElements(oldPos, newPos); - [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels); - - this.render({ - positions: oldPos, - calcLabels: newLabels - }); - - return this.store.map((line, i) => { - return translateVertLine( - line, newPos[i], oldPos[i] - ); - }); - } - }, - - yMarkers: { - layerClass: 'y-markers', - makeElements(data) { - return data.map(m => - yMarker(m.position, m.label, this.constants.width, - {labelPos: m.options.labelPos, mode: 'span', lineType: 'dashed'}) - ); - }, - animateElements(newData) { - [this.oldData, newData] = equilizeNoOfElements(this.oldData, newData); - - let newPos = newData.map(d => d.position); - let newLabels = newData.map(d => d.label); - let newOptions = newData.map(d => d.options); - - let oldPos = this.oldData.map(d => d.position); - - this.render(oldPos.map((pos, i) => { - return { - position: oldPos[i], - label: newLabels[i], - options: newOptions[i] - }; - })); - - return this.store.map((line, i) => { - return translateHoriLine( - line, newPos[i], oldPos[i] - ); - }); - } - }, - - yRegions: { - layerClass: 'y-regions', - makeElements(data) { - return data.map(r => - yRegion(r.startPos, r.endPos, this.constants.width, - r.label, {labelPos: r.options.labelPos}) - ); - }, - animateElements(newData) { - [this.oldData, newData] = equilizeNoOfElements(this.oldData, newData); - - let newPos = newData.map(d => d.endPos); - let newLabels = newData.map(d => d.label); - let newStarts = newData.map(d => d.startPos); - let newOptions = newData.map(d => d.options); - - let oldPos = this.oldData.map(d => d.endPos); - let oldStarts = this.oldData.map(d => d.startPos); - - this.render(oldPos.map((pos, i) => { - return { - startPos: oldStarts[i], - endPos: oldPos[i], - label: newLabels[i], - options: newOptions[i] - }; - })); - - let animateElements = []; - - this.store.map((rectGroup, i) => { - animateElements = animateElements.concat(animateRegion( - rectGroup, newStarts[i], newPos[i], oldPos[i] - )); - }); - - return animateElements; - } - }, - - heatDomain: { - layerClass: function() { return 'heat-domain domain-' + this.constants.index; }, - makeElements(data) { - let {index, colWidth, rowHeight, squareSize, radius, xTranslate} = this.constants; - let monthNameHeight = -12; - let x = xTranslate, y = 0; - - this.serializedSubDomains = []; - - data.cols.map((week, weekNo) => { - if(weekNo === 1) { - this.labels.push( - makeText('domain-name', x, monthNameHeight, getMonthName(index, true).toUpperCase(), - { - fontSize: 9 - } - ) - ); - } - week.map((day, i) => { - if(day.fill) { - let data = { - 'data-date': day.yyyyMmDd, - 'data-value': day.dataValue, - 'data-day': i - }; - let square = heatSquare('day', x, y, squareSize, radius, day.fill, data); - this.serializedSubDomains.push(square); - } - y += rowHeight; - }); - y = 0; - x += colWidth; - }); - - return this.serializedSubDomains; - }, - - animateElements(newData) { - if(newData) return []; - } - }, - - barGraph: { - layerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; }, - makeElements(data) { - let c = this.constants; - this.unitType = 'bar'; - this.units = data.yPositions.map((y, j) => { - return datasetBar( - data.xPositions[j], - y, - data.barWidth, - c.color, - data.labels[j], - j, - data.offsets[j], - { - zeroLine: data.zeroLine, - barsWidth: data.barsWidth, - minHeight: c.minHeight - } - ); - }); - return this.units; - }, - animateElements(newData) { - let newXPos = newData.xPositions; - let newYPos = newData.yPositions; - let newOffsets = newData.offsets; - let newLabels = newData.labels; - - let oldXPos = this.oldData.xPositions; - let oldYPos = this.oldData.yPositions; - let oldOffsets = this.oldData.offsets; - let oldLabels = this.oldData.labels; - - [oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos); - [oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos); - [oldOffsets, newOffsets] = equilizeNoOfElements(oldOffsets, newOffsets); - [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels); - - this.render({ - xPositions: oldXPos, - yPositions: oldYPos, - offsets: oldOffsets, - labels: newLabels, - - zeroLine: this.oldData.zeroLine, - barsWidth: this.oldData.barsWidth, - barWidth: this.oldData.barWidth, - }); - - let animateElements = []; - - this.store.map((bar, i) => { - animateElements = animateElements.concat(animateBar( - bar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i], - {zeroLine: newData.zeroLine} - )); - }); - - return animateElements; - } - }, - - lineGraph: { - layerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; }, - makeElements(data) { - let c = this.constants; - this.unitType = 'dot'; - this.paths = {}; - if(!c.hideLine) { - this.paths = getPaths( - data.xPositions, - data.yPositions, - c.color, - { - heatline: c.heatline, - regionFill: c.regionFill, - spline: c.spline - }, - { - svgDefs: c.svgDefs, - zeroLine: data.zeroLine - } - ); - } - - this.units = []; - if(!c.hideDots) { - this.units = data.yPositions.map((y, j) => { - return datasetDot( - data.xPositions[j], - y, - data.radius, - c.color, - (c.valuesOverPoints ? data.values[j] : ''), - j - ); - }); - } - - return Object.values(this.paths).concat(this.units); - }, - animateElements(newData) { - let newXPos = newData.xPositions; - let newYPos = newData.yPositions; - let newValues = newData.values; - - let oldXPos = this.oldData.xPositions; - let oldYPos = this.oldData.yPositions; - let oldValues = this.oldData.values; - - [oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos); - [oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos); - [oldValues, newValues] = equilizeNoOfElements(oldValues, newValues); - - this.render({ - xPositions: oldXPos, - yPositions: oldYPos, - values: newValues, - - zeroLine: this.oldData.zeroLine, - radius: this.oldData.radius, - }); - - let animateElements = []; - - if(Object.keys(this.paths).length) { - animateElements = animateElements.concat(animatePath( - this.paths, newXPos, newYPos, newData.zeroLine, this.constants.spline)); - } - - if(this.units.length) { - this.units.map((dot, i) => { - animateElements = animateElements.concat(animateDot( - dot, newXPos[i], newYPos[i])); - }); - } - - return animateElements; - } - } -}; - -function getComponent(name, constants, getData) { - let keys = Object.keys(componentConfigs).filter(k => name.includes(k)); - let config = componentConfigs[keys[0]]; - Object.assign(config, { - constants: constants, - getData: getData - }); - return new ChartComponent(config); -} - -class PercentageChart extends AggregationChart { - constructor(parent, args) { - super(parent, args); - this.type = 'percentage'; - this.setup(); - } - - setMeasures(options) { - let m = this.measures; - this.barOptions = options.barOptions || {}; - - let b = this.barOptions; - b.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT; - b.depth = b.depth || PERCENTAGE_BAR_DEFAULT_DEPTH; - - m.paddings.right = 30; - m.legendHeight = 60; - m.baseHeight = (b.height + b.depth * 0.5) * 8; - } - - setupComponents() { - let s = this.state; - - let componentConfigs = [ - [ - 'percentageBars', - { - barHeight: this.barOptions.height, - barDepth: this.barOptions.depth, - }, - function() { - return { - xPositions: s.xPositions, - widths: s.widths, - colors: this.colors - }; - }.bind(this) - ] - ]; - - this.components = new Map(componentConfigs - .map(args => { - let component = getComponent(...args); - return [args[0], component]; - })); - } - - calc() { - super.calc(); - let s = this.state; - - s.xPositions = []; - s.widths = []; - - let xPos = 0; - s.sliceTotals.map((value) => { - let width = this.width * value / s.grandTotal; - s.widths.push(width); - s.xPositions.push(xPos); - xPos += width; - }); - } - - makeDataByIndex() { } - - bindTooltip() { - let s = this.state; - this.container.addEventListener('mousemove', (e) => { - let bars = this.components.get('percentageBars').store; - let bar = e.target; - if(bars.includes(bar)) { - - let i = bars.indexOf(bar); - let gOff = getOffset(this.container), pOff = getOffset(bar); - - let x = pOff.left - gOff.left + parseInt(bar.getAttribute('width'))/2; - let y = pOff.top - gOff.top; - let title = (this.formattedLabels && this.formattedLabels.length>0 - ? this.formattedLabels[i] : this.state.labels[i]) + ': '; - let fraction = s.sliceTotals[i]/s.grandTotal; - - this.tip.setValues(x, y, {name: title, value: (fraction*100).toFixed(1) + "%"}); - this.tip.showTip(); - } - }); - } -} - -class PieChart extends AggregationChart { - constructor(parent, args) { - super(parent, args); - this.type = 'pie'; - this.initTimeout = 0; - this.init = 1; - - this.setup(); - } - - configure(args) { - super.configure(args); - this.mouseMove = this.mouseMove.bind(this); - this.mouseLeave = this.mouseLeave.bind(this); - - this.hoverRadio = args.hoverRadio || 0.1; - this.config.startAngle = args.startAngle || 0; - - this.clockWise = args.clockWise || false; - } - - calc() { - super.calc(); - let s = this.state; - this.radius = (this.height > this.width ? this.center.x : this.center.y); - - const { radius, clockWise } = this; - - const prevSlicesProperties = s.slicesProperties || []; - s.sliceStrings = []; - s.slicesProperties = []; - let curAngle = 180 - this.config.startAngle; - s.sliceTotals.map((total, i) => { - const startAngle = curAngle; - const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE; - const largeArc = originDiffAngle > 180 ? 1: 0; - const diffAngle = clockWise ? -originDiffAngle : originDiffAngle; - const endAngle = curAngle = curAngle + diffAngle; - const startPosition = getPositionByAngle(startAngle, radius); - const endPosition = getPositionByAngle(endAngle, radius); - - const prevProperty = this.init && prevSlicesProperties[i]; - - let curStart,curEnd; - if(this.init) { - curStart = prevProperty ? prevProperty.startPosition : startPosition; - curEnd = prevProperty ? prevProperty.endPosition : startPosition; - } else { - curStart = startPosition; - curEnd = endPosition; - } - const curPath = - originDiffAngle === 360 - ? makeCircleStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc) - : makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc); - - s.sliceStrings.push(curPath); - s.slicesProperties.push({ - startPosition, - endPosition, - value: total, - total: s.grandTotal, - startAngle, - endAngle, - angle: diffAngle - }); - - }); - this.init = 0; - } - - setupComponents() { - let s = this.state; - - let componentConfigs = [ - [ - 'pieSlices', - { }, - function() { - return { - sliceStrings: s.sliceStrings, - colors: this.colors - }; - }.bind(this) - ] - ]; - - this.components = new Map(componentConfigs - .map(args => { - let component = getComponent(...args); - return [args[0], component]; - })); - } - - calTranslateByAngle(property){ - const{radius,hoverRadio} = this; - const position = getPositionByAngle(property.startAngle+(property.angle / 2),radius); - return `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`; - } - - hoverSlice(path,i,flag,e){ - if(!path) return; - const color = this.colors[i]; - if(flag) { - transform(path, this.calTranslateByAngle(this.state.slicesProperties[i])); - path.style.fill = lightenDarkenColor(color, 50); - let g_off = getOffset(this.svg); - let x = e.pageX - g_off.left + 10; - let y = e.pageY - g_off.top - 10; - let title = (this.formatted_labels && this.formatted_labels.length > 0 - ? this.formatted_labels[i] : this.state.labels[i]) + ': '; - let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1); - this.tip.setValues(x, y, {name: title, value: percent + "%"}); - this.tip.showTip(); - } else { - transform(path,'translate3d(0,0,0)'); - this.tip.hideTip(); - path.style.fill = color; - } - } - - bindTooltip() { - this.container.addEventListener('mousemove', this.mouseMove); - this.container.addEventListener('mouseleave', this.mouseLeave); - } - - mouseMove(e){ - const target = e.target; - let slices = this.components.get('pieSlices').store; - let prevIndex = this.curActiveSliceIndex; - let prevAcitve = this.curActiveSlice; - if(slices.includes(target)) { - let i = slices.indexOf(target); - this.hoverSlice(prevAcitve, prevIndex,false); - this.curActiveSlice = target; - this.curActiveSliceIndex = i; - this.hoverSlice(target, i, true, e); - } else { - this.mouseLeave(); - } - } - - mouseLeave(){ - this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false); - } -} - -function normalize(x) { - // Calculates mantissa and exponent of a number - // Returns normalized number and exponent - // https://stackoverflow.com/q/9383593/6495043 - - if(x===0) { - return [0, 0]; - } - if(isNaN(x)) { - return {mantissa: -6755399441055744, exponent: 972}; - } - var sig = x > 0 ? 1 : -1; - if(!isFinite(x)) { - return {mantissa: sig * 4503599627370496, exponent: 972}; - } - - x = Math.abs(x); - var exp = Math.floor(Math.log10(x)); - var man = x/Math.pow(10, exp); - - return [sig * man, exp]; -} - -function getChartRangeIntervals(max, min=0) { - let upperBound = Math.ceil(max); - let lowerBound = Math.floor(min); - let range = upperBound - lowerBound; - - let noOfParts = range; - let partSize = 1; - - // To avoid too many partitions - if(range > 5) { - if(range % 2 !== 0) { - upperBound++; - // Recalc range - range = upperBound - lowerBound; - } - noOfParts = range/2; - partSize = 2; - } - - // Special case: 1 and 2 - if(range <= 2) { - noOfParts = 4; - partSize = range/noOfParts; - } - - // Special case: 0 - if(range === 0) { - noOfParts = 5; - partSize = 1; - } - - let intervals = []; - for(var i = 0; i <= noOfParts; i++){ - intervals.push(lowerBound + partSize * i); - } - return intervals; -} - -function getChartIntervals(maxValue, minValue=0) { - let [normalMaxValue, exponent] = normalize(maxValue); - let normalMinValue = minValue ? minValue/Math.pow(10, exponent): 0; - - // Allow only 7 significant digits - normalMaxValue = normalMaxValue.toFixed(6); - - let intervals = getChartRangeIntervals(normalMaxValue, normalMinValue); - intervals = intervals.map(value => value * Math.pow(10, exponent)); - return intervals; -} - -function calcChartIntervals(values, withMinimum=false) { - //*** Where the magic happens *** - - // Calculates best-fit y intervals from given values - // and returns the interval array - - let maxValue = Math.max(...values); - let minValue = Math.min(...values); - - // Exponent to be used for pretty print - let exponent = 0, intervals = []; // eslint-disable-line no-unused-vars - - function getPositiveFirstIntervals(maxValue, absMinValue) { - let intervals = getChartIntervals(maxValue); - - let intervalSize = intervals[1] - intervals[0]; - - // Then unshift the negative values - let value = 0; - for(var i = 1; value < absMinValue; i++) { - value += intervalSize; - intervals.unshift((-1) * value); - } - return intervals; - } - - // CASE I: Both non-negative - - if(maxValue >= 0 && minValue >= 0) { - exponent = normalize(maxValue)[1]; - if(!withMinimum) { - intervals = getChartIntervals(maxValue); - } else { - intervals = getChartIntervals(maxValue, minValue); - } - } - - // CASE II: Only minValue negative - - else if(maxValue > 0 && minValue < 0) { - // `withMinimum` irrelevant in this case, - // We'll be handling both sides of zero separately - // (both starting from zero) - // Because ceil() and floor() behave differently - // in those two regions - - let absMinValue = Math.abs(minValue); - - if(maxValue >= absMinValue) { - exponent = normalize(maxValue)[1]; - intervals = getPositiveFirstIntervals(maxValue, absMinValue); - } else { - // Mirror: maxValue => absMinValue, then change sign - exponent = normalize(absMinValue)[1]; - let posIntervals = getPositiveFirstIntervals(absMinValue, maxValue); - intervals = posIntervals.reverse().map(d => d * (-1)); - } - - } - - // CASE III: Both non-positive - - else if(maxValue <= 0 && minValue <= 0) { - // Mirrored Case I: - // Work with positives, then reverse the sign and array - - let pseudoMaxValue = Math.abs(minValue); - let pseudoMinValue = Math.abs(maxValue); - - exponent = normalize(pseudoMaxValue)[1]; - if(!withMinimum) { - intervals = getChartIntervals(pseudoMaxValue); - } else { - intervals = getChartIntervals(pseudoMaxValue, pseudoMinValue); - } - - intervals = intervals.reverse().map(d => d * (-1)); - } - - return intervals; -} - -function getZeroIndex(yPts) { - let zeroIndex; - let interval = getIntervalSize(yPts); - if(yPts.indexOf(0) >= 0) { - // the range has a given zero - // zero-line on the chart - zeroIndex = yPts.indexOf(0); - } else if(yPts[0] > 0) { - // Minimum value is positive - // zero-line is off the chart: below - let min = yPts[0]; - zeroIndex = (-1) * min / interval; - } else { - // Maximum value is negative - // zero-line is off the chart: above - let max = yPts[yPts.length - 1]; - zeroIndex = (-1) * max / interval + (yPts.length - 1); - } - return zeroIndex; -} - - - -function getIntervalSize(orderedArray) { - return orderedArray[1] - orderedArray[0]; -} - -function getValueRange(orderedArray) { - return orderedArray[orderedArray.length-1] - orderedArray[0]; -} - -function scale(val, yAxis) { - return floatTwo(yAxis.zeroLine - val * yAxis.scaleMultiplier); -} - - - - - -function getClosestInArray(goal, arr, index = false) { - let closest = arr.reduce(function(prev, curr) { - return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev); - }, []); - - return index ? arr.indexOf(closest) : closest; -} - -function calcDistribution(values, distributionSize) { - // Assume non-negative values, - // implying distribution minimum at zero - - let dataMaxValue = Math.max(...values); - - let distributionStep = 1 / (distributionSize - 1); - let distribution = []; - - for(var i = 0; i < distributionSize; i++) { - let checkpoint = dataMaxValue * (distributionStep * i); - distribution.push(checkpoint); - } - - return distribution; -} - -function getMaxCheckpoint(value, distribution) { - return distribution.filter(d => d < value).length; -} - -const COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE; -const ROW_HEIGHT = COL_WIDTH; -// const DAY_INCR = 1; - -class Heatmap extends BaseChart { - constructor(parent, options) { - super(parent, options); - this.type = 'heatmap'; - - this.countLabel = options.countLabel || ''; - - let validStarts = ['Sunday', 'Monday']; - let startSubDomain = validStarts.includes(options.startSubDomain) - ? options.startSubDomain : 'Sunday'; - this.startSubDomainIndex = validStarts.indexOf(startSubDomain); - - this.setup(); - } - - setMeasures(options) { - let m = this.measures; - this.discreteDomains = options.discreteDomains === 0 ? 0 : 1; - - m.paddings.top = ROW_HEIGHT * 3; - m.paddings.bottom = 0; - m.legendHeight = ROW_HEIGHT * 2; - m.baseHeight = ROW_HEIGHT * NO_OF_DAYS_IN_WEEK - + getExtraHeight(m); - - let d = this.data; - let spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0; - this.independentWidth = (getWeeksBetween(d.start, d.end) - + spacing) * COL_WIDTH + getExtraWidth(m); - } - - updateWidth() { - let spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0; - let noOfWeeks = this.state.noOfWeeks ? this.state.noOfWeeks : 52; - this.baseWidth = (noOfWeeks + spacing) * COL_WIDTH - + getExtraWidth(this.measures); - } - - prepareData(data=this.data) { - if(data.start && data.end && data.start > data.end) { - throw new Error('Start date cannot be greater than end date.'); - } - - if(!data.start) { - data.start = new Date(); - data.start.setFullYear( data.start.getFullYear() - 1 ); - } - if(!data.end) { data.end = new Date(); } - data.dataPoints = data.dataPoints || {}; - - if(parseInt(Object.keys(data.dataPoints)[0]) > 100000) { - let points = {}; - Object.keys(data.dataPoints).forEach(timestampSec$$1 => { - let date = new Date(timestampSec$$1 * NO_OF_MILLIS); - points[getYyyyMmDd(date)] = data.dataPoints[timestampSec$$1]; - }); - data.dataPoints = points; - } - - return data; - } - - calc() { - let s = this.state; - - s.start = clone(this.data.start); - s.end = clone(this.data.end); - - s.firstWeekStart = clone(s.start); - s.noOfWeeks = getWeeksBetween(s.start, s.end); - s.distribution = calcDistribution( - Object.values(this.data.dataPoints), HEATMAP_DISTRIBUTION_SIZE); - - s.domainConfigs = this.getDomains(); - } - - setupComponents() { - let s = this.state; - let lessCol = this.discreteDomains ? 0 : 1; - - let componentConfigs = s.domainConfigs.map((config, i) => [ - 'heatDomain', - { - index: config.index, - colWidth: COL_WIDTH, - rowHeight: ROW_HEIGHT, - squareSize: HEATMAP_SQUARE_SIZE, - radius: this.rawChartArgs.radius || 0, - xTranslate: s.domainConfigs - .filter((config, j) => j < i) - .map(config => config.cols.length - lessCol) - .reduce((a, b) => a + b, 0) - * COL_WIDTH - }, - function() { - return s.domainConfigs[i]; - }.bind(this) - - ]); - - this.components = new Map(componentConfigs - .map((args, i) => { - let component = getComponent(...args); - return [args[0] + '-' + i, component]; - }) - ); - - let y = 0; - DAY_NAMES_SHORT.forEach((dayName, i) => { - if([1, 3, 5].includes(i)) { - let dayText = makeText('subdomain-name', -COL_WIDTH/2, y, dayName, - { - fontSize: HEATMAP_SQUARE_SIZE, - dy: 8, - textAnchor: 'end' - } - ); - this.drawArea.appendChild(dayText); - } - y += ROW_HEIGHT; - }); - } - - update(data) { - if(!data) { - console.error('No data to update.'); - } - - this.data = this.prepareData(data); - this.draw(); - this.bindTooltip(); - } - - bindTooltip() { - this.container.addEventListener('mousemove', (e) => { - this.components.forEach(comp => { - let daySquares = comp.store; - let daySquare = e.target; - if(daySquares.includes(daySquare)) { - - let count = daySquare.getAttribute('data-value'); - let dateParts = daySquare.getAttribute('data-date').split('-'); - - let month = getMonthName(parseInt(dateParts[1])-1, true); - - let gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect(); - - let width = parseInt(e.target.getAttribute('width')); - let x = pOff.left - gOff.left + width/2; - let y = pOff.top - gOff.top; - let value = count + ' ' + this.countLabel; - let name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2]; - - this.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []); - this.tip.showTip(); - } - }); - }); - } - - renderLegend() { - this.legendArea.textContent = ''; - let x = 0; - let y = ROW_HEIGHT; - let radius = this.rawChartArgs.radius || 0; - - let lessText = makeText('subdomain-name', x, y, 'Less', - { - fontSize: HEATMAP_SQUARE_SIZE + 1, - dy: 9 - } - ); - x = (COL_WIDTH * 2) + COL_WIDTH/2; - this.legendArea.appendChild(lessText); - - this.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map((color, i) => { - const square = heatSquare('heatmap-legend-unit', x + (COL_WIDTH + 3) * i, - y, HEATMAP_SQUARE_SIZE, radius, color); - this.legendArea.appendChild(square); - }); - - let moreTextX = x + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH/4; - let moreText = makeText('subdomain-name', moreTextX, y, 'More', - { - fontSize: HEATMAP_SQUARE_SIZE + 1, - dy: 9 - } - ); - this.legendArea.appendChild(moreText); - } - - getDomains() { - let s = this.state; - const [startMonth, startYear] = [s.start.getMonth(), s.start.getFullYear()]; - const [endMonth, endYear] = [s.end.getMonth(), s.end.getFullYear()]; - - const noOfMonths = (endMonth - startMonth + 1) + (endYear - startYear) * 12; - - let domainConfigs = []; - - let startOfMonth = clone(s.start); - for(var i = 0; i < noOfMonths; i++) { - let endDate = s.end; - if(!areInSameMonth(startOfMonth, s.end)) { - let [month, year] = [startOfMonth.getMonth(), startOfMonth.getFullYear()]; - endDate = getLastDateInMonth(month, year); - } - domainConfigs.push(this.getDomainConfig(startOfMonth, endDate)); - - addDays(endDate, 1); - startOfMonth = endDate; - } - - return domainConfigs; - } - - getDomainConfig(startDate, endDate='') { - let [month, year] = [startDate.getMonth(), startDate.getFullYear()]; - let startOfWeek = setDayToSunday(startDate); // TODO: Monday as well - endDate = clone(endDate) || getLastDateInMonth(month, year); - - let domainConfig = { - index: month, - cols: [] - }; - - addDays(endDate, 1); - let noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate); - - let cols = [], col; - for(var i = 0; i < noOfMonthWeeks; i++) { - col = this.getCol(startOfWeek, month); - cols.push(col); - - startOfWeek = new Date(col[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd); - addDays(startOfWeek, 1); - } - - if(col[NO_OF_DAYS_IN_WEEK - 1].dataValue !== undefined) { - addDays(startOfWeek, 1); - cols.push(this.getCol(startOfWeek, month, true)); - } - - domainConfig.cols = cols; - - return domainConfig; - } - - getCol(startDate, month, empty = false) { - let s = this.state; - - // startDate is the start of week - let currentDate = clone(startDate); - let col = []; - - for(var i = 0; i < NO_OF_DAYS_IN_WEEK; i++, addDays(currentDate, 1)) { - let config = {}; - - // Non-generic adjustment for entire heatmap, needs state - let currentDateWithinData = currentDate >= s.start && currentDate <= s.end; - - if(empty || currentDate.getMonth() !== month || !currentDateWithinData) { - config.yyyyMmDd = getYyyyMmDd(currentDate); - } else { - config = this.getSubDomainConfig(currentDate); - } - col.push(config); - } - - return col; - } - - getSubDomainConfig(date) { - let yyyyMmDd = getYyyyMmDd(date); - let dataValue = this.data.dataPoints[yyyyMmDd]; - let config = { - yyyyMmDd: yyyyMmDd, - dataValue: dataValue || 0, - fill: this.colors[getMaxCheckpoint(dataValue, this.state.distribution)] - }; - return config; - } -} - -function dataPrep(data, type) { - data.labels = data.labels || []; - - let datasetLength = data.labels.length; - - // Datasets - let datasets = data.datasets; - let zeroArray = new Array(datasetLength).fill(0); - if(!datasets) { - // default - datasets = [{ - values: zeroArray - }]; - } - - datasets.map(d=> { - // Set values - if(!d.values) { - d.values = zeroArray; - } else { - // Check for non values - let vals = d.values; - vals = vals.map(val => (!isNaN(val) ? val : 0)); - - // Trim or extend - if(vals.length > datasetLength) { - vals = vals.slice(0, datasetLength); - } else { - vals = fillArray(vals, datasetLength - vals.length, 0); - } - d.values = vals; - } - - // Set type - if(!d.chartType ) { - if(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE; - d.chartType = type; - } - - }); - - // Markers - - // Regions - // data.yRegions = data.yRegions || []; - if(data.yRegions) { - data.yRegions.map(d => { - if(d.end < d.start) { - [d.start, d.end] = [d.end, d.start]; - } - }); - } - - return data; -} - -function zeroDataPrep(realData) { - let datasetLength = realData.labels.length; - let zeroArray = new Array(datasetLength).fill(0); - - let zeroData = { - labels: realData.labels.slice(0, -1), - datasets: realData.datasets.map(d => { - return { - name: '', - values: zeroArray.slice(0, -1), - chartType: d.chartType - }; - }), - }; - - if(realData.yMarkers) { - zeroData.yMarkers = [ - { - value: 0, - label: '' - } - ]; - } - - if(realData.yRegions) { - zeroData.yRegions = [ - { - start: 0, - end: 0, - label: '' - } - ]; - } - - return zeroData; -} - -function getShortenedLabels(chartWidth, labels=[], isSeries=true) { - let allowedSpace = chartWidth / labels.length; - if(allowedSpace <= 0) allowedSpace = 1; - let allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH; - - let seriesMultiple; - if(isSeries) { - // Find the maximum label length for spacing calculations - let maxLabelLength = Math.max(...labels.map(label => label.length)); - seriesMultiple = Math.ceil(maxLabelLength/allowedLetters); - } - - let calcLabels = labels.map((label, i) => { - label += ""; - if(label.length > allowedLetters) { - - if(!isSeries) { - if(allowedLetters-3 > 0) { - label = label.slice(0, allowedLetters-3) + " ..."; - } else { - label = label.slice(0, allowedLetters) + '..'; - } - } else { - if(i % seriesMultiple !== 0) { - label = ""; - } - } - } - return label; - }); - - return calcLabels; -} - -class AxisChart extends BaseChart { - constructor(parent, args) { - super(parent, args); - - this.barOptions = args.barOptions || {}; - this.lineOptions = args.lineOptions || {}; - - this.type = args.type || 'line'; - this.init = 1; - - this.setup(); - } - - setMeasures() { - if(this.data.datasets.length <= 1) { - this.config.showLegend = 0; - this.measures.paddings.bottom = 30; - } - } - - configure(options) { - super.configure(options); - - options.axisOptions = options.axisOptions || {}; - options.tooltipOptions = options.tooltipOptions || {}; - - this.config.xAxisMode = options.axisOptions.xAxisMode || 'span'; - this.config.yAxisMode = options.axisOptions.yAxisMode || 'span'; - this.config.xIsSeries = options.axisOptions.xIsSeries || 0; - this.config.shortenYAxisNumbers = options.axisOptions.shortenYAxisNumbers || 0; - - this.config.formatTooltipX = options.tooltipOptions.formatTooltipX; - this.config.formatTooltipY = options.tooltipOptions.formatTooltipY; - - this.config.valuesOverPoints = options.valuesOverPoints; - } - - prepareData(data=this.data) { - return dataPrep(data, this.type); - } - - prepareFirstData(data=this.data) { - return zeroDataPrep(data); - } - - calc(onlyWidthChange = false) { - this.calcXPositions(); - if(!onlyWidthChange) { - this.calcYAxisParameters(this.getAllYValues(), this.type === 'line'); - } - this.makeDataByIndex(); - } - - calcXPositions() { - let s = this.state; - let labels = this.data.labels; - s.datasetLength = labels.length; - - s.unitWidth = this.width/(s.datasetLength); - // Default, as per bar, and mixed. Only line will be a special case - s.xOffset = s.unitWidth/2; - - // // For a pure Line Chart - // s.unitWidth = this.width/(s.datasetLength - 1); - // s.xOffset = 0; - - s.xAxis = { - labels: labels, - positions: labels.map((d, i) => - floatTwo(s.xOffset + i * s.unitWidth) - ) - }; - } - - calcYAxisParameters(dataValues, withMinimum = 'false') { - const yPts = calcChartIntervals(dataValues, withMinimum); - const scaleMultiplier = this.height / getValueRange(yPts); - const intervalHeight = getIntervalSize(yPts) * scaleMultiplier; - const zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight); - - this.state.yAxis = { - labels: yPts, - positions: yPts.map(d => zeroLine - d * scaleMultiplier), - scaleMultiplier: scaleMultiplier, - zeroLine: zeroLine, - }; - - // Dependent if above changes - this.calcDatasetPoints(); - this.calcYExtremes(); - this.calcYRegions(); - } - - calcDatasetPoints() { - let s = this.state; - let scaleAll = values => values.map(val => scale(val, s.yAxis)); - - s.datasets = this.data.datasets.map((d, i) => { - let values = d.values; - let cumulativeYs = d.cumulativeYs || []; - return { - name: d.name && d.name.replace(/<|>|&/g, (char) => char == '&' ? '&' : char == '<' ? '<' : '>'), - index: i, - chartType: d.chartType, - - values: values, - yPositions: scaleAll(values), - - cumulativeYs: cumulativeYs, - cumulativeYPos: scaleAll(cumulativeYs), - }; - }); - } - - calcYExtremes() { - let s = this.state; - if(this.barOptions.stacked) { - s.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos; - return; - } - s.yExtremes = new Array(s.datasetLength).fill(9999); - s.datasets.map(d => { - d.yPositions.map((pos, j) => { - if(pos < s.yExtremes[j]) { - s.yExtremes[j] = pos; - } - }); - }); - } - - calcYRegions() { - let s = this.state; - if(this.data.yMarkers) { - this.state.yMarkers = this.data.yMarkers.map(d => { - d.position = scale(d.value, s.yAxis); - if(!d.options) d.options = {}; - // if(!d.label.includes(':')) { - // d.label += ': ' + d.value; - // } - return d; - }); - } - if(this.data.yRegions) { - this.state.yRegions = this.data.yRegions.map(d => { - d.startPos = scale(d.start, s.yAxis); - d.endPos = scale(d.end, s.yAxis); - if(!d.options) d.options = {}; - return d; - }); - } - } - - getAllYValues() { - let key = 'values'; - - if(this.barOptions.stacked) { - key = 'cumulativeYs'; - let cumulative = new Array(this.state.datasetLength).fill(0); - this.data.datasets.map((d, i) => { - let values = this.data.datasets[i].values; - d[key] = cumulative = cumulative.map((c, i) => c + values[i]); - }); - } - - let allValueLists = this.data.datasets.map(d => d[key]); - if(this.data.yMarkers) { - allValueLists.push(this.data.yMarkers.map(d => d.value)); - } - if(this.data.yRegions) { - this.data.yRegions.map(d => { - allValueLists.push([d.end, d.start]); - }); - } - - return [].concat(...allValueLists); - } - - setupComponents() { - let componentConfigs = [ - [ - 'yAxis', - { - mode: this.config.yAxisMode, - width: this.width, - shortenNumbers: this.config.shortenYAxisNumbers - // pos: 'right' - }, - function() { - return this.state.yAxis; - }.bind(this) - ], - - [ - 'xAxis', - { - mode: this.config.xAxisMode, - height: this.height, - // pos: 'right' - }, - function() { - let s = this.state; - s.xAxis.calcLabels = getShortenedLabels(this.width, - s.xAxis.labels, this.config.xIsSeries); - - return s.xAxis; - }.bind(this) - ], - - [ - 'yRegions', - { - width: this.width, - pos: 'right' - }, - function() { - return this.state.yRegions; - }.bind(this) - ], - ]; - - let barDatasets = this.state.datasets.filter(d => d.chartType === 'bar'); - let lineDatasets = this.state.datasets.filter(d => d.chartType === 'line'); - - let barsConfigs = barDatasets.map(d => { - let index = d.index; - return [ - 'barGraph' + '-' + d.index, - { - index: index, - color: this.colors[index], - stacked: this.barOptions.stacked, - - // same for all datasets - valuesOverPoints: this.config.valuesOverPoints, - minHeight: this.height * MIN_BAR_PERCENT_HEIGHT, - }, - function() { - let s = this.state; - let d = s.datasets[index]; - let stacked = this.barOptions.stacked; - - let spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO; - let barsWidth = s.unitWidth * (1 - spaceRatio); - let barWidth = barsWidth/(stacked ? 1 : barDatasets.length); - - let xPositions = s.xAxis.positions.map(x => x - barsWidth/2); - if(!stacked) { - xPositions = xPositions.map(p => p + barWidth * index); - } - - let labels = new Array(s.datasetLength).fill(''); - if(this.config.valuesOverPoints) { - if(stacked && d.index === s.datasets.length - 1) { - labels = d.cumulativeYs; - } else { - labels = d.values; - } - } - - let offsets = new Array(s.datasetLength).fill(0); - if(stacked) { - offsets = d.yPositions.map((y, j) => y - d.cumulativeYPos[j]); - } - - return { - xPositions: xPositions, - yPositions: d.yPositions, - offsets: offsets, - // values: d.values, - labels: labels, - - zeroLine: s.yAxis.zeroLine, - barsWidth: barsWidth, - barWidth: barWidth, - }; - }.bind(this) - ]; - }); - - let lineConfigs = lineDatasets.map(d => { - let index = d.index; - return [ - 'lineGraph' + '-' + d.index, - { - index: index, - color: this.colors[index], - svgDefs: this.svgDefs, - heatline: this.lineOptions.heatline, - regionFill: this.lineOptions.regionFill, - spline: this.lineOptions.spline, - hideDots: this.lineOptions.hideDots, - hideLine: this.lineOptions.hideLine, - - // same for all datasets - valuesOverPoints: this.config.valuesOverPoints, - }, - function() { - let s = this.state; - let d = s.datasets[index]; - let minLine = s.yAxis.positions[0] < s.yAxis.zeroLine - ? s.yAxis.positions[0] : s.yAxis.zeroLine; - - return { - xPositions: s.xAxis.positions, - yPositions: d.yPositions, - - values: d.values, - - zeroLine: minLine, - radius: this.lineOptions.dotSize || LINE_CHART_DOT_SIZE, - }; - }.bind(this) - ]; - }); - - let markerConfigs = [ - [ - 'yMarkers', - { - width: this.width, - pos: 'right' - }, - function() { - return this.state.yMarkers; - }.bind(this) - ] - ]; - - componentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs); - - let optionals = ['yMarkers', 'yRegions']; - this.dataUnitComponents = []; - - this.components = new Map(componentConfigs - .filter(args => !optionals.includes(args[0]) || this.state[args[0]]) - .map(args => { - let component = getComponent(...args); - if(args[0].includes('lineGraph') || args[0].includes('barGraph')) { - this.dataUnitComponents.push(component); - } - return [args[0], component]; - })); - } - - makeDataByIndex() { - this.dataByIndex = {}; - - let s = this.state; - let formatX = this.config.formatTooltipX; - let formatY = this.config.formatTooltipY; - let titles = s.xAxis.labels; - - titles.map((label, index) => { - let values = this.state.datasets.map((set, i) => { - let value = set.values[index]; - return { - title: set.name, - value: value, - yPos: set.yPositions[index], - color: this.colors[i], - formatted: formatY ? formatY(value) : value, - }; - }); - - this.dataByIndex[index] = { - label: label, - formattedLabel: formatX ? formatX(label) : label, - xPos: s.xAxis.positions[index], - values: values, - yExtreme: s.yExtremes[index], - }; - }); - } - - bindTooltip() { - // NOTE: could be in tooltip itself, as it is a given functionality for its parent - this.container.addEventListener('mousemove', (e) => { - let m = this.measures; - let o = getOffset(this.container); - let relX = e.pageX - o.left - getLeftOffset(m); - let relY = e.pageY - o.top; - - if(relY < this.height + getTopOffset(m) - && relY > getTopOffset(m)) { - this.mapTooltipXPosition(relX); - } else { - this.tip.hideTip(); - } - }); - } - - mapTooltipXPosition(relX) { - let s = this.state; - if(!s.yExtremes) return; - - let index = getClosestInArray(relX, s.xAxis.positions, true); - if (index >= 0) { - let dbi = this.dataByIndex[index]; - - this.tip.setValues( - dbi.xPos + this.tip.offset.x, - dbi.yExtreme + this.tip.offset.y, - {name: dbi.formattedLabel, value: ''}, - dbi.values, - index - ); - - this.tip.showTip(); - } - } - - renderLegend() { - let s = this.data; - if(s.datasets.length > 1) { - this.legendArea.textContent = ''; - s.datasets.map((d, i) => { - let barWidth = AXIS_LEGEND_BAR_SIZE; - // let rightEndPoint = this.baseWidth - this.measures.margins.left - this.measures.margins.right; - // let multiplier = s.datasets.length - i; - let rect = legendBar( - // rightEndPoint - multiplier * barWidth, // To right align - barWidth * i, - '0', - barWidth, - this.colors[i], - d.name, - this.config.truncateLegends); - this.legendArea.appendChild(rect); - }); - } - } - - - - // Overlay - makeOverlay() { - if(this.init) { - this.init = 0; - return; - } - if(this.overlayGuides) { - this.overlayGuides.forEach(g => { - let o = g.overlay; - o.parentNode.removeChild(o); - }); - } - - this.overlayGuides = this.dataUnitComponents.map(c => { - return { - type: c.unitType, - overlay: undefined, - units: c.units, - }; - }); - - if(this.state.currentIndex === undefined) { - this.state.currentIndex = this.state.datasetLength - 1; - } - - // Render overlays - this.overlayGuides.map(d => { - let currentUnit = d.units[this.state.currentIndex]; - - d.overlay = makeOverlay[d.type](currentUnit); - this.drawArea.appendChild(d.overlay); - }); - } - - updateOverlayGuides() { - if(this.overlayGuides) { - this.overlayGuides.forEach(g => { - let o = g.overlay; - o.parentNode.removeChild(o); - }); - } - } - - bindOverlay() { - this.parent.addEventListener('data-select', () => { - this.updateOverlay(); - }); - } - - bindUnits() { - this.dataUnitComponents.map(c => { - c.units.map(unit => { - unit.addEventListener('click', () => { - let index = unit.getAttribute('data-point-index'); - this.setCurrentDataPoint(index); - }); - }); - }); - - // Note: Doesn't work as tooltip is absolutely positioned - this.tip.container.addEventListener('click', () => { - let index = this.tip.container.getAttribute('data-point-index'); - this.setCurrentDataPoint(index); - }); - } - - updateOverlay() { - this.overlayGuides.map(d => { - let currentUnit = d.units[this.state.currentIndex]; - updateOverlay[d.type](currentUnit, d.overlay); - }); - } - - onLeftArrow() { - this.setCurrentDataPoint(this.state.currentIndex - 1); - } - - onRightArrow() { - this.setCurrentDataPoint(this.state.currentIndex + 1); - } - - getDataPoint(index=this.state.currentIndex) { - let s = this.state; - let data_point = { - index: index, - label: s.xAxis.labels[index], - values: s.datasets.map(d => d.values[index]) - }; - return data_point; - } - - setCurrentDataPoint(index) { - let s = this.state; - index = parseInt(index); - if(index < 0) index = 0; - if(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1; - if(index === s.currentIndex) return; - s.currentIndex = index; - fire(this.parent, "data-select", this.getDataPoint()); - } - - - - // API - addDataPoint(label, datasetValues, index=this.state.datasetLength) { - super.addDataPoint(label, datasetValues, index); - this.data.labels.splice(index, 0, label); - this.data.datasets.map((d, i) => { - d.values.splice(index, 0, datasetValues[i]); - }); - this.update(this.data); - } - - removeDataPoint(index = this.state.datasetLength-1) { - if (this.data.labels.length <= 1) { - return; - } - super.removeDataPoint(index); - this.data.labels.splice(index, 1); - this.data.datasets.map(d => { - d.values.splice(index, 1); - }); - this.update(this.data); - } - - updateDataset(datasetValues, index=0) { - this.data.datasets[index].values = datasetValues; - this.update(this.data); - } - // addDataset(dataset, index) {} - // removeDataset(index = 0) {} - - updateDatasets(datasets) { - this.data.datasets.map((d, i) => { - if(datasets[i]) { - d.values = datasets[i]; - } - }); - this.update(this.data); - } - - // updateDataPoint(dataPoint, index = 0) {} - // addDataPoint(dataPoint, index = 0) {} - // removeDataPoint(index = 0) {} -} - -class DonutChart extends AggregationChart { - constructor(parent, args) { - super(parent, args); - this.type = 'donut'; - this.initTimeout = 0; - this.init = 1; - - this.setup(); - } - - configure(args) { - super.configure(args); - this.mouseMove = this.mouseMove.bind(this); - this.mouseLeave = this.mouseLeave.bind(this); - - this.hoverRadio = args.hoverRadio || 0.1; - this.config.startAngle = args.startAngle || 0; - - this.clockWise = args.clockWise || false; - this.strokeWidth = args.strokeWidth || 30; - } - - calc() { - super.calc(); - let s = this.state; - this.radius = - this.height > this.width - ? this.center.x - this.strokeWidth / 2 - : this.center.y - this.strokeWidth / 2; - - const { radius, clockWise } = this; - - const prevSlicesProperties = s.slicesProperties || []; - s.sliceStrings = []; - s.slicesProperties = []; - let curAngle = 180 - this.config.startAngle; - - s.sliceTotals.map((total, i) => { - const startAngle = curAngle; - const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE; - const largeArc = originDiffAngle > 180 ? 1: 0; - const diffAngle = clockWise ? -originDiffAngle : originDiffAngle; - const endAngle = curAngle = curAngle + diffAngle; - const startPosition = getPositionByAngle(startAngle, radius); - const endPosition = getPositionByAngle(endAngle, radius); - - const prevProperty = this.init && prevSlicesProperties[i]; - - let curStart,curEnd; - if(this.init) { - curStart = prevProperty ? prevProperty.startPosition : startPosition; - curEnd = prevProperty ? prevProperty.endPosition : startPosition; - } else { - curStart = startPosition; - curEnd = endPosition; - } - const curPath = - originDiffAngle === 360 - ? makeStrokeCircleStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc) - : makeArcStrokePathStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc); - - s.sliceStrings.push(curPath); - s.slicesProperties.push({ - startPosition, - endPosition, - value: total, - total: s.grandTotal, - startAngle, - endAngle, - angle: diffAngle - }); - - }); - this.init = 0; - } - - setupComponents() { - let s = this.state; - - let componentConfigs = [ - [ - 'donutSlices', - { }, - function() { - return { - sliceStrings: s.sliceStrings, - colors: this.colors, - strokeWidth: this.strokeWidth, - }; - }.bind(this) - ] - ]; - - this.components = new Map(componentConfigs - .map(args => { - let component = getComponent(...args); - return [args[0], component]; - })); - } - - calTranslateByAngle(property){ - const{ radius, hoverRadio } = this; - const position = getPositionByAngle(property.startAngle+(property.angle / 2),radius); - return `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`; - } - - hoverSlice(path,i,flag,e){ - if(!path) return; - const color = this.colors[i]; - if(flag) { - transform(path, this.calTranslateByAngle(this.state.slicesProperties[i])); - path.style.stroke = lightenDarkenColor(color, 50); - let g_off = getOffset(this.svg); - let x = e.pageX - g_off.left + 10; - let y = e.pageY - g_off.top - 10; - let title = (this.formatted_labels && this.formatted_labels.length > 0 - ? this.formatted_labels[i] : this.state.labels[i]) + ': '; - let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1); - this.tip.setValues(x, y, {name: title, value: percent + "%"}); - this.tip.showTip(); - } else { - transform(path,'translate3d(0,0,0)'); - this.tip.hideTip(); - path.style.stroke = color; - } - } - - bindTooltip() { - this.container.addEventListener('mousemove', this.mouseMove); - this.container.addEventListener('mouseleave', this.mouseLeave); - } - - mouseMove(e){ - const target = e.target; - let slices = this.components.get('donutSlices').store; - let prevIndex = this.curActiveSliceIndex; - let prevAcitve = this.curActiveSlice; - if(slices.includes(target)) { - let i = slices.indexOf(target); - this.hoverSlice(prevAcitve, prevIndex,false); - this.curActiveSlice = target; - this.curActiveSliceIndex = i; - this.hoverSlice(target, i, true, e); - } else { - this.mouseLeave(); - } - } - - mouseLeave(){ - this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false); - } -} - -// import MultiAxisChart from './charts/MultiAxisChart'; -const chartTypes = { - bar: AxisChart, - line: AxisChart, - // multiaxis: MultiAxisChart, - percentage: PercentageChart, - heatmap: Heatmap, - pie: PieChart, - donut: DonutChart, -}; - -function getChartByType(chartType = 'line', parent, options) { - if (chartType === 'axis-mixed') { - options.type = 'line'; - return new AxisChart(parent, options); - } - - if (!chartTypes[chartType]) { - console.error("Undefined chart type: " + chartType); - return; - } - - return new chartTypes[chartType](parent, options); -} - -class Chart { - constructor(parent, options) { - return getChartByType(options.type, parent, options); - } -} - -export { Chart, PercentageChart, PieChart, Heatmap, AxisChart }; diff --git a/node_modules/frappe-charts/dist/frappe-charts.min.cjs.js b/node_modules/frappe-charts/dist/frappe-charts.min.cjs.js deleted file mode 100644 index 1ea7974..0000000 --- a/node_modules/frappe-charts/dist/frappe-charts.min.cjs.js +++ /dev/null @@ -1,2 +0,0 @@ -"use strict";function styleInject(t,e){void 0===e&&(e={});var n=e.insertAt;if(t&&"undefined"!=typeof document){var i=document.head||document.getElementsByTagName("head")[0],a=document.createElement("style");a.type="text/css","top"===n&&i.firstChild?i.insertBefore(a,i.firstChild):i.appendChild(a),a.styleSheet?a.styleSheet.cssText=t:a.appendChild(document.createTextNode(t))}}function $(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function getOffset(t){var e=t.getBoundingClientRect();return{top:e.top+(document.documentElement.scrollTop||document.body.scrollTop),left:e.left+(document.documentElement.scrollLeft||document.body.scrollLeft)}}function isHidden(t){return null===t.offsetParent}function isElementInViewport(t){var e=t.getBoundingClientRect();return e.top>=0&&e.left>=0&&e.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&e.right<=(window.innerWidth||document.documentElement.clientWidth)}function getElementContentWidth(t){var e=window.getComputedStyle(t),n=parseFloat(e.paddingLeft)+parseFloat(e.paddingRight);return t.clientWidth-n}function fire(t,e,n){var i=document.createEvent("HTMLEvents");i.initEvent(e,!0,!0);for(var a in n)i[a]=n[a];return t.dispatchEvent(i)}function getTopOffset(t){return t.titleHeight+t.margins.top+t.paddings.top}function getLeftOffset(t){return t.margins.left+t.paddings.left}function getExtraHeight(t){return t.margins.top+t.margins.bottom+t.paddings.top+t.paddings.bottom+t.titleHeight+t.legendHeight}function getExtraWidth(t){return t.margins.left+t.margins.right+t.paddings.left+t.paddings.right}function _classCallCheck$4(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function floatTwo(t){return parseFloat(t.toFixed(2))}function fillArray(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]&&arguments[3];n||(n=i?t[0]:t[t.length-1]);var a=new Array(Math.abs(e)).fill(n);return t=i?a.concat(t):t.concat(a)}function getStringWidth(t,e){return(t+"").length*e}function getPositionByAngle(t,e){return{x:Math.sin(t*ANGLE_RATIO)*e,y:Math.cos(t*ANGLE_RATIO)*e}}function isValidNumber(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return!Number.isNaN(t)&&(void 0!==t&&(!!Number.isFinite(t)&&!(e&&t<0)))}function round(t){return Number(Math.round(t+"e4")+"e-4")}function deepClone(t){var e=void 0,n=void 0,i=void 0;if(t instanceof Date)return new Date(t.getTime());if("object"!==(void 0===t?"undefined":_typeof$2(t))||null===t)return t;e=Array.isArray(t)?[]:{};for(i in t)n=t[i],e[i]=deepClone(n);return e}function getBarHeightAndYAttr(t,e){var n=void 0,i=void 0;return t<=e?(n=e-t,i=t):(n=t-e,i=e),[n,i]}function equilizeNoOfElements(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:e.length-t.length;return n>0?t=fillArray(t,n):e=fillArray(e,n),[t,e]}function truncateString(t,e){if(t)return t.length>e?t.slice(0,e-3)+"...":t}function shortenLargeNumber(t){var e=void 0;if("number"==typeof t)e=t;else if("string"==typeof t&&(e=Number(t),Number.isNaN(e)))return t;var n=Math.floor(Math.log10(Math.abs(e)));if(n<=2)return e;var i=Math.floor(n/3),a=Math.pow(10,n-3*i)*+(e/Math.pow(10,n)).toFixed(1);return Math.round(100*a)/100+" "+["","K","M","B","T"][i]}function getSplineCurvePointsStr(t,e){for(var n=[],i=0;i255?255:t<0?0:t}function lightenDarkenColor(t,e){var n=getColor(t),i=!1;"#"==n[0]&&(n=n.slice(1),i=!0);var a=parseInt(n,16),r=limitColor((a>>16)+e),o=limitColor((a>>8&255)+e),s=limitColor((255&a)+e);return(i?"#":"")+(s|o<<8|r<<16).toString(16)}function isValidColor(t){var e=/(^\s*)(rgb|hsl)(a?)[(]\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*(?:,\s*([\d.]+)\s*)?[)]$/i;return/(^\s*)(#)((?:[A-Fa-f0-9]{3}){1,2})$/i.test(t)||e.test(t)}function $$1(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function createSVG(t,e){var n=document.createElementNS("http://www.w3.org/2000/svg",t);for(var i in e){var a=e[i];if("inside"===i)$$1(a).appendChild(n);else if("around"===i){var r=$$1(a);r.parentNode.insertBefore(n,r),n.appendChild(r)}else"styles"===i?"object"===(void 0===a?"undefined":_typeof$1(a))&&Object.keys(a).map(function(t){n.style[t]=a[t]}):("className"===i&&(i="class"),"innerHTML"===i?n.textContent=a:n.setAttribute(i,a))}return n}function renderVerticalGradient(t,e){return createSVG("linearGradient",{inside:t,id:e,x1:0,x2:0,y1:0,y2:1})}function setGradientStop(t,e,n,i){return createSVG("stop",{inside:t,style:"stop-color: "+n,offset:e,"stop-opacity":i})}function makeSVGContainer(t,e,n,i){return createSVG("svg",{className:e,inside:t,width:n,height:i})}function makeSVGDefs(t){return createSVG("defs",{inside:t})}function makeSVGGroup(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0,i={className:t,transform:e};return n&&(i.inside=n),createSVG("g",i)}function makePath(t){return createSVG("path",{className:arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",d:t,styles:{stroke:arguments.length>2&&void 0!==arguments[2]?arguments[2]:"none",fill:arguments.length>3&&void 0!==arguments[3]?arguments[3]:"none","stroke-width":arguments.length>4&&void 0!==arguments[4]?arguments[4]:2}})}function makeArcPathStr(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=n.x+t.x,s=n.y+t.y,l=n.x+e.x,u=n.y+e.y;return"M"+n.x+" "+n.y+"\n\t\tL"+o+" "+s+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+u+" z"}function makeCircleStr(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=n.x+t.x,s=n.y+t.y,l=n.x+e.x,u=2*n.y,c=n.y+e.y;return"M"+n.x+" "+n.y+"\n\t\tL"+o+" "+s+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+u+" z\n\t\tL"+o+" "+u+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+c+" z"}function makeArcStrokePathStr(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=n.x+t.x,s=n.y+t.y,l=n.x+e.x,u=n.y+e.y;return"M"+o+" "+s+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+u}function makeStrokeCircleStr(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=n.x+t.x,s=n.y+t.y,l=n.x+e.x,u=2*i+s,c=n.y+t.y;return"M"+o+" "+s+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+u+"\n\t\tM"+o+" "+u+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+c}function makeGradient(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i="path-fill-gradient-"+e+"-"+(n?"lighter":"default"),a=renderVerticalGradient(t,i),r=[1,.6,.2];return n&&(r=[.4,.2,0]),setGradientStop(a,"0%",e,r[0]),setGradientStop(a,"50%",e,r[1]),setGradientStop(a,"100%",e,r[2]),i}function percentageBar(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:PERCENTAGE_BAR_DEFAULT_DEPTH,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:"none";return createSVG("rect",{className:"percentage-bar",x:t,y:e,width:n,height:i,fill:r,styles:{stroke:lightenDarkenColor(r,-25),"stroke-dasharray":"0, "+(i+n)+", "+n+", "+i,"stroke-width":a}})}function heatSquare(t,e,n,i,a){var r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:"none",o=arguments.length>6&&void 0!==arguments[6]?arguments[6]:{},s={className:t,x:e,y:n,width:i,height:i,rx:a,fill:r};return Object.keys(o).map(function(t){s[t]=o[t]}),createSVG("rect",s)}function legendBar(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"none",a=arguments[4];a=arguments.length>5&&void 0!==arguments[5]&&arguments[5]?truncateString(a,LABEL_MAX_CHARS):a;var r={className:"legend-bar",x:0,y:0,width:n,height:"2px",fill:i},o=createSVG("text",{className:"legend-dataset-text",x:0,y:0,dy:2*FONT_SIZE+"px","font-size":1.2*FONT_SIZE+"px","text-anchor":"start",fill:FONT_FILL,innerHTML:a}),s=createSVG("g",{transform:"translate("+t+", "+e+")"});return s.appendChild(createSVG("rect",r)),s.appendChild(o),s}function legendDot(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"none",a=arguments[4];a=arguments.length>5&&void 0!==arguments[5]&&arguments[5]?truncateString(a,LABEL_MAX_CHARS):a;var r={className:"legend-dot",cx:0,cy:0,r:n,fill:i},o=createSVG("text",{className:"legend-dataset-text",x:0,y:0,dx:FONT_SIZE+"px",dy:FONT_SIZE/3+"px","font-size":1.2*FONT_SIZE+"px","text-anchor":"start",fill:FONT_FILL,innerHTML:a}),s=createSVG("g",{transform:"translate("+t+", "+e+")"});return s.appendChild(createSVG("circle",r)),s.appendChild(o),s}function makeText(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},r=a.fontSize||FONT_SIZE;return createSVG("text",{className:t,x:e,y:n,dy:(void 0!==a.dy?a.dy:r/2)+"px","font-size":r+"px",fill:a.fill||FONT_FILL,"text-anchor":a.textAnchor||"start",innerHTML:i})}function makeVertLine(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};a.stroke||(a.stroke=BASE_LINE_COLOR);var r=createSVG("line",{className:"line-vertical "+a.className,x1:0,x2:0,y1:n,y2:i,styles:{stroke:a.stroke}}),o=createSVG("text",{x:0,y:n>i?n+LABEL_MARGIN:n-LABEL_MARGIN-FONT_SIZE,dy:FONT_SIZE+"px","font-size":FONT_SIZE+"px","text-anchor":"middle",innerHTML:e+""}),s=createSVG("g",{transform:"translate("+t+", 0)"});return s.appendChild(r),s.appendChild(o),s}function makeHoriLine(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};a.stroke||(a.stroke=BASE_LINE_COLOR),a.lineType||(a.lineType=""),a.shortenNumbers&&(e=shortenLargeNumber(e));var r=createSVG("line",{className:"line-horizontal "+a.className+("dashed"===a.lineType?"dashed":""),x1:n,x2:i,y1:0,y2:0,styles:{stroke:a.stroke}}),o=createSVG("text",{x:n3&&void 0!==arguments[3]?arguments[3]:{};isValidNumber(t)||(t=0),i.pos||(i.pos="left"),i.offset||(i.offset=0),i.mode||(i.mode="span"),i.stroke||(i.stroke=BASE_LINE_COLOR),i.className||(i.className="");var a=-1*AXIS_TICK_LENGTH,r="span"===i.mode?n+AXIS_TICK_LENGTH:0;return"tick"===i.mode&&"right"===i.pos&&(a=n+AXIS_TICK_LENGTH,r=n),a+=i.offset,r+=i.offset,makeHoriLine(t,e,a,r,{stroke:i.stroke,className:i.className,lineType:i.lineType,shortenNumbers:i.shortenNumbers})}function xLine(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};isValidNumber(t)||(t=0),i.pos||(i.pos="bottom"),i.offset||(i.offset=0),i.mode||(i.mode="span"),i.stroke||(i.stroke=BASE_LINE_COLOR),i.className||(i.className="");var a=n+AXIS_TICK_LENGTH,r="span"===i.mode?-1*AXIS_TICK_LENGTH:n;return"tick"===i.mode&&"top"===i.pos&&(a=-1*AXIS_TICK_LENGTH,r=0),makeVertLine(t,e,a,r,{stroke:i.stroke,className:i.className,lineType:i.lineType})}function yMarker(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};i.labelPos||(i.labelPos="right");var a=createSVG("text",{className:"chart-label",x:"left"===i.labelPos?LABEL_MARGIN:n-getStringWidth(e,5)-LABEL_MARGIN,y:0,dy:FONT_SIZE/-2+"px","font-size":FONT_SIZE+"px","text-anchor":"start",innerHTML:e+""}),r=makeHoriLine(t,"",0,n,{stroke:i.stroke||BASE_LINE_COLOR,className:i.className||"",lineType:i.lineType});return r.appendChild(a),r}function yRegion(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},r=t-e,o=createSVG("rect",{className:"bar mini",styles:{fill:"rgba(228, 234, 239, 0.49)",stroke:BASE_LINE_COLOR,"stroke-dasharray":n+", "+r},x:0,y:0,width:n,height:r});a.labelPos||(a.labelPos="right");var s=createSVG("text",{className:"chart-label",x:"left"===a.labelPos?LABEL_MARGIN:n-getStringWidth(i+"",4.5)-LABEL_MARGIN,y:0,dy:FONT_SIZE/-2+"px","font-size":FONT_SIZE+"px","text-anchor":"start",innerHTML:i+""}),l=createSVG("g",{transform:"translate(0, "+e+")"});return l.appendChild(o),l.appendChild(s),l}function datasetBar(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"",r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=arguments.length>6&&void 0!==arguments[6]?arguments[6]:0,s=arguments.length>7&&void 0!==arguments[7]?arguments[7]:{},l=getBarHeightAndYAttr(e,s.zeroLine),u=_slicedToArray(l,2),c=u[0],h=u[1];h-=o,0===c&&(c=s.minHeight,h-=s.minHeight),isValidNumber(t)||(t=0),isValidNumber(h)||(h=0),isValidNumber(c,!0)||(c=0),isValidNumber(n,!0)||(n=0);var d=createSVG("rect",{className:"bar mini",style:"fill: "+i,"data-point-index":r,x:t,y:h,width:n,height:c});if((a+="")||a.length){d.setAttribute("y",0),d.setAttribute("x",0);var f=createSVG("text",{className:"data-point-value",x:n/2,y:0,dy:FONT_SIZE/2*-1+"px","font-size":FONT_SIZE+"px","text-anchor":"middle",innerHTML:a}),p=createSVG("g",{"data-point-index":r,transform:"translate("+t+", "+h+")"});return p.appendChild(d),p.appendChild(f),p}return d}function datasetDot(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"",r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=createSVG("circle",{style:"fill: "+i,"data-point-index":r,cx:t,cy:e,r:n});if((a+="")||a.length){o.setAttribute("cy",0),o.setAttribute("cx",0);var s=createSVG("text",{className:"data-point-value",x:0,y:0,dy:FONT_SIZE/2*-1-n+"px","font-size":FONT_SIZE+"px","text-anchor":"middle",innerHTML:a}),l=createSVG("g",{"data-point-index":r,transform:"translate("+t+", "+e+")"});return l.appendChild(o),l.appendChild(s),l}return o}function getPaths(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},r=e.map(function(e,n){return t[n]+","+e}).join("L");i.spline&&(r=getSplineCurvePointsStr(t,e));var o=makePath("M"+r,"line-graph-path",n);if(i.heatline){var s=makeGradient(a.svgDefs,n);o.style.stroke="url(#"+s+")"}var l={path:o};if(i.regionFill){var u=makeGradient(a.svgDefs,n,!0),c="M"+t[0]+","+a.zeroLine+"L"+r+"L"+t.slice(-1)[0]+","+a.zeroLine;l.region=makePath(c,"region-fill","none","url(#"+u+")")}return l}function translate(t,e,n,i){var a="string"==typeof e?e:e.join(", ");return[t,{transform:n.join(", ")},i,STD_EASING,"translate",{transform:a}]}function translateVertLine(t,e,n){return translate(t,[n,0],[e,0],MARKER_LINE_ANIM_DUR)}function translateHoriLine(t,e,n){return translate(t,[0,n],[0,e],MARKER_LINE_ANIM_DUR)}function animateRegion(t,e,n,i){var a=e-n,r=t.childNodes[0];return[[r,{height:a,"stroke-dasharray":r.getAttribute("width")+", "+a},MARKER_LINE_ANIM_DUR,STD_EASING],translate(t,[0,i],[0,n],MARKER_LINE_ANIM_DUR)]}function animateBar(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0,r=getBarHeightAndYAttr(n,(arguments.length>5&&void 0!==arguments[5]?arguments[5]:{}).zeroLine),o=_slicedToArray$2(r,2),s=o[0],l=o[1];return l-=a,"rect"!==t.nodeName?[[t.childNodes[0],{width:i,height:s},UNIT_ANIM_DUR,STD_EASING],translate(t,t.getAttribute("transform").split("(")[1].slice(0,-1),[e,l],MARKER_LINE_ANIM_DUR)]:[[t,{width:i,height:s,x:e,y:l},UNIT_ANIM_DUR,STD_EASING]]}function animateDot(t,e,n){return"circle"!==t.nodeName?[translate(t,t.getAttribute("transform").split("(")[1].slice(0,-1),[e,n],MARKER_LINE_ANIM_DUR)]:[[t,{cx:e,cy:n},UNIT_ANIM_DUR,STD_EASING]]}function animatePath(t,e,n,i,a){var r=[],o=n.map(function(t,n){return e[n]+","+t}).join("L");a&&(o=getSplineCurvePointsStr(e,n));var s=[t.path,{d:"M"+o},PATH_ANIM_DUR,STD_EASING];if(r.push(s),t.region){var l=e[0]+","+i+"L",u="L"+e.slice(-1)[0]+", "+i,c=[t.region,{d:"M"+l+o+u},PATH_ANIM_DUR,STD_EASING];r.push(c)}return r}function animatePathStr(t,e){return[t,{d:e},UNIT_ANIM_DUR,STD_EASING]}function _toConsumableArray$1(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e3&&void 0!==arguments[3]?arguments[3]:"linear",a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:void 0,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:{},o=t.cloneNode(!0),s=t.cloneNode(!0);for(var l in e){var u=void 0;u="transform"===l?document.createElementNS("http://www.w3.org/2000/svg","animateTransform"):document.createElementNS("http://www.w3.org/2000/svg","animate");var c=r[l]||t.getAttribute(l),h=e[l],d={attributeName:l,from:c,to:h,begin:"0s",dur:n/1e3+"s",values:c+";"+h,keySplines:EASING[i],keyTimes:"0;1",calcMode:"spline",fill:"freeze"};a&&(d.type=a);for(var f in d)u.setAttribute(f,d[f]);o.appendChild(u),a?s.setAttribute(l,"translate("+h+")"):s.setAttribute(l,h)}return[o,s]}function transform(t,e){t.style.transform=e,t.style.webkitTransform=e,t.style.msTransform=e,t.style.mozTransform=e,t.style.oTransform=e}function animateSVG(t,e){var n=[],i=[];e.map(function(t){var e=t[0],a=e.parentNode,r=void 0,o=void 0;t[0]=e;var s=animateSVGElement.apply(void 0,_toConsumableArray$1(t)),l=_slicedToArray$1(s,2);r=l[0],o=l[1],n.push(o),i.push([r,a]),a&&a.replaceChild(r,e)});var a=t.cloneNode(!0);return i.map(function(t,i){t[1]&&(t[1].replaceChild(n[i],t[0]),e[i][0]=n[i])}),a}function runSMILAnimation(t,e,n){if(0!==n.length){var i=animateSVG(e,n);e.parentNode==t&&(t.removeChild(e),t.appendChild(i)),setTimeout(function(){i.parentNode==t&&(t.removeChild(i),t.appendChild(e))},REPLACE_ALL_NEW_DUR)}}function downloadFile(t,e){var n=document.createElement("a");n.style="display: none";var i=new Blob(e,{type:"image/svg+xml; charset=utf-8"}),a=window.URL.createObjectURL(i);n.href=a,n.download=t,document.body.appendChild(n),n.click(),setTimeout(function(){document.body.removeChild(n),window.URL.revokeObjectURL(a)},300)}function prepareForExport(t){var e=t.cloneNode(!0);e.classList.add("chart-container"),e.setAttribute("xmlns","http://www.w3.org/2000/svg"),e.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink");var n=$.create("style",{innerHTML:CSSTEXT});e.insertBefore(n,e.firstChild);var i=$.create("div");return i.appendChild(e),i.innerHTML}function _classCallCheck$3(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function _classCallCheck$2(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn$1(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function _inherits$1(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function treatAsUtc(t){var e=new Date(t);return e.setMinutes(e.getMinutes()-e.getTimezoneOffset()),e}function getYyyyMmDd(t){var e=t.getDate(),n=t.getMonth()+1;return[t.getFullYear(),(n>9?"":"0")+n,(e>9?"":"0")+e].join("-")}function clone(t){return new Date(t.getTime())}function getWeeksBetween(t,e){var n=setDayToSunday(t);return Math.ceil(getDaysBetween(n,e)/NO_OF_DAYS_IN_WEEK)}function getDaysBetween(t,e){var n=SEC_IN_DAY*NO_OF_MILLIS;return(treatAsUtc(e)-treatAsUtc(t))/n}function areInSameMonth(t,e){return t.getMonth()===e.getMonth()&&t.getFullYear()===e.getFullYear()}function getMonthName(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=MONTH_NAMES[t];return e?n.slice(0,3):n}function getLastDateInMonth(t,e){return new Date(e,t+1,0)}function setDayToSunday(t){var e=clone(t),n=e.getDay();return 0!==n&&addDays(e,-1*n),e}function addDays(t,e){t.setDate(t.getDate()+e)}function _classCallCheck$5(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function getComponent(t,e,n){var i=Object.keys(componentConfigs).filter(function(e){return t.includes(e)}),a=componentConfigs[i[0]];return Object.assign(a,{constants:e,getData:n}),new ChartComponent(a)}function _toConsumableArray(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e0?1:-1;if(!isFinite(t))return{mantissa:4503599627370496*e,exponent:972};t=Math.abs(t);var n=Math.floor(Math.log10(t));return[e*(t/Math.pow(10,n)),n]}function getChartRangeIntervals(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=Math.ceil(t),i=Math.floor(e),a=n-i,r=a,o=1;a>5&&(a%2!=0&&(a=++n-i),r=a/2,o=2),a<=2&&(o=a/(r=4)),0===a&&(r=5,o=1);for(var s=[],l=0;l<=r;l++)s.push(i+o*l);return s}function getChartIntervals(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=normalize(t),i=_slicedToArray$4(n,2),a=i[0],r=i[1],o=e?e/Math.pow(10,r):0,s=getChartRangeIntervals(a=a.toFixed(6),o);return s=s.map(function(t){return t*Math.pow(10,r)})}function calcChartIntervals(t){function e(t,e){for(var n=getChartIntervals(t),i=n[1]-n[0],a=0,r=1;a1&&void 0!==arguments[1]&&arguments[1],i=Math.max.apply(Math,_toConsumableArray$4(t)),a=Math.min.apply(Math,_toConsumableArray$4(t)),r=[];if(i>=0&&a>=0)normalize(i)[1],r=n?getChartIntervals(i,a):getChartIntervals(i);else if(i>0&&a<0){var o=Math.abs(a);i>=o?(normalize(i)[1],r=e(i,o)):(normalize(o)[1],r=e(o,i).reverse().map(function(t){return-1*t}))}else if(i<=0&&a<=0){var s=Math.abs(a),l=Math.abs(i);normalize(s)[1],r=(r=n?getChartIntervals(s,l):getChartIntervals(s)).reverse().map(function(t){return-1*t})}return r}function getZeroIndex(t){var e=getIntervalSize(t);return t.indexOf(0)>=0?t.indexOf(0):t[0]>0?-1*t[0]/e:-1*t[t.length-1]/e+(t.length-1)}function getIntervalSize(t){return t[1]-t[0]}function getValueRange(t){return t[t.length-1]-t[0]}function scale(t,e){return floatTwo(e.zeroLine-t*e.scaleMultiplier)}function getClosestInArray(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=e.reduce(function(e,n){return Math.abs(n-t)n?i.slice(0,n):fillArray(i,n-i.length,0),t.values=i}else t.values=a;t.chartType||(AXIS_DATASET_CHART_TYPES.includes(e),t.chartType=e)}),t.yRegions&&t.yRegions.map(function(t){if(t.end1&&void 0!==arguments[1]?arguments[1]:[],n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],i=t/e.length;i<=0&&(i=1);var a=i/DEFAULT_CHAR_WIDTH,r=void 0;if(n){var o=Math.max.apply(Math,_toConsumableArray$6(e.map(function(t){return t.length})));r=Math.ceil(o/a)}return e.map(function(t,e){return(t+="").length>a&&(n?e%r!=0&&(t=""):t=a-3>0?t.slice(0,a-3)+" ...":t.slice(0,a)+".."),t})}function _toConsumableArray$5(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e0&&void 0!==arguments[0]?arguments[0]:"line",e=arguments[1],n=arguments[2];return"axis-mixed"===t?(n.type="line",new AxisChart(e,n)):chartTypes[t]?new chartTypes[t](e,n):void console.error("Undefined chart type: "+t)}Object.defineProperty(exports,"__esModule",{value:!0});var css_248z='.chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ol,.graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}';styleInject(css_248z);var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};$.create=function(t,e){var n=document.createElement(t);for(var i in e){var a=e[i];if("inside"===i)$(a).appendChild(n);else if("around"===i){var r=$(a);r.parentNode.insertBefore(n,r),n.appendChild(r)}else"styles"===i?"object"===(void 0===a?"undefined":_typeof(a))&&Object.keys(a).map(function(t){n.style[t]=a[t]}):i in n?n[i]=a:n.setAttribute(i,a)}return n};var BASE_MEASURES={margins:{top:10,bottom:10,left:20,right:20},paddings:{top:20,bottom:40,left:30,right:10},baseHeight:240,titleHeight:20,legendHeight:30,titleFontSize:12},INIT_CHART_UPDATE_TIMEOUT=700,CHART_POST_ANIMATE_TIMEOUT=400,DEFAULT_AXIS_CHART_TYPE="line",AXIS_DATASET_CHART_TYPES=["line","bar"],AXIS_LEGEND_BAR_SIZE=100,BAR_CHART_SPACE_RATIO=.5,MIN_BAR_PERCENT_HEIGHT=0,LINE_CHART_DOT_SIZE=4,DOT_OVERLAY_SIZE_INCR=4,PERCENTAGE_BAR_DEFAULT_HEIGHT=20,PERCENTAGE_BAR_DEFAULT_DEPTH=2,HEATMAP_DISTRIBUTION_SIZE=5,HEATMAP_SQUARE_SIZE=10,HEATMAP_GUTTER_SIZE=2,DEFAULT_CHAR_WIDTH=7,TOOLTIP_POINTER_TRIANGLE_HEIGHT=5,DEFAULT_CHART_COLORS=["light-blue","blue","violet","red","orange","yellow","green","light-green","purple","magenta","light-grey","dark-grey"],HEATMAP_COLORS_GREEN=["#ebedf0","#c6e48b","#7bc96f","#239a3b","#196127"],DEFAULT_COLORS={bar:DEFAULT_CHART_COLORS,line:DEFAULT_CHART_COLORS,pie:DEFAULT_CHART_COLORS,percentage:DEFAULT_CHART_COLORS,heatmap:HEATMAP_COLORS_GREEN,donut:DEFAULT_CHART_COLORS},ANGLE_RATIO=Math.PI/180,FULL_ANGLE=360,_createClass$3=function(){function t(t,e){for(var n=0;n\n\t\t\t\t
      \n\t\t\t\t
      '}),this.hideTip(),this.title=this.container.querySelector(".title"),this.dataPointList=this.container.querySelector(".data-point-list"),this.parent.addEventListener("mouseleave",function(){t.hideTip()})}},{key:"fill",value:function(){var t=this,e=void 0;this.index&&this.container.setAttribute("data-point-index",this.index),e=this.titleValueFirst?""+this.titleValue+""+this.titleName:this.titleName+""+this.titleValue+"",this.title.innerHTML=e,this.dataPointList.innerHTML="",this.listValues.map(function(e,n){var i=t.colors[n]||"black",a=0===e.formatted||e.formatted?e.formatted:e.value,r=$.create("li",{styles:{"border-top":"3px solid "+i},innerHTML:''+(0===a||a?a:"")+"\n\t\t\t\t\t"+(e.title?e.title:"")});t.dataPointList.appendChild(r)})}},{key:"calcPosition",value:function(){var t=this.container.offsetWidth;this.top=this.y-this.container.offsetHeight-TOOLTIP_POINTER_TRIANGLE_HEIGHT,this.left=this.x-t/2;var e=this.parent.offsetWidth-t,n=this.container.querySelector(".svg-pointer");if(this.left<0)n.style.left="calc(50% - "+-1*this.left+"px)",this.left=0;else if(this.left>e){var i="calc(50% + "+(this.left-e)+"px)";n.style.left=i,this.left=e}else n.style.left="50%"}},{key:"setValues",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[],a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:-1;this.titleName=n.name,this.titleValue=n.value,this.listValues=i,this.x=t,this.y=e,this.titleValueFirst=n.valueFirst||0,this.index=a,this.refresh()}},{key:"hideTip",value:function(){this.container.style.top="0px",this.container.style.left="0px",this.container.style.opacity="0"}},{key:"showTip",value:function(){this.container.style.top=this.top+"px",this.container.style.left=this.left+"px",this.container.style.opacity="1"}}]),t}(),_typeof$2="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},PRESET_COLOR_MAP={"light-blue":"#7cd6fd",blue:"#5e64ff",violet:"#743ee2",red:"#ff5858",orange:"#ffa00a",yellow:"#feef72",green:"#28a745","light-green":"#98d85b",purple:"#b554ff",magenta:"#ffa3ef",black:"#36114C",grey:"#bdd3e6","light-grey":"#f0f4f7","dark-grey":"#b8c2cc"},getColor=function(t){return/rgb[a]{0,1}\([\d, ]+\)/gim.test(t)?/\D+(\d*)\D+(\d*)\D+(\d*)/gim.exec(t).map(function(t,e){return 0!==e?Number(t).toString(16):"#"}).reduce(function(t,e){return""+t+e}):PRESET_COLOR_MAP[t]||t},_slicedToArray=function(){function t(t,e){var n=[],i=!0,a=!1,r=void 0;try{for(var o,s=t[Symbol.iterator]();!(i=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);i=!0);}catch(t){a=!0,r=t}finally{try{!i&&s.return&&s.return()}finally{if(a)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_typeof$1="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},AXIS_TICK_LENGTH=6,LABEL_MARGIN=4,LABEL_MAX_CHARS=15,FONT_SIZE=10,BASE_LINE_COLOR="#dadada",FONT_FILL="#555b51",makeOverlay={bar:function(t){var e=void 0;"rect"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);var n=t.cloneNode();return n.style.fill="#000000",n.style.opacity="0.4",e&&n.setAttribute("transform",e),n},dot:function(t){var e=void 0;"circle"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);var n=t.cloneNode(),i=t.getAttribute("r"),a=t.getAttribute("fill");return n.setAttribute("r",parseInt(i)+DOT_OVERLAY_SIZE_INCR),n.setAttribute("fill",a),n.style.opacity="0.6",e&&n.setAttribute("transform",e),n},heat_square:function(t){var e=void 0;"circle"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);var n=t.cloneNode(),i=t.getAttribute("r"),a=t.getAttribute("fill");return n.setAttribute("r",parseInt(i)+DOT_OVERLAY_SIZE_INCR),n.setAttribute("fill",a),n.style.opacity="0.6",e&&n.setAttribute("transform",e),n}},updateOverlay={bar:function(t,e){var n=void 0;"rect"!==t.nodeName&&(n=t.getAttribute("transform"),t=t.childNodes[0]);var i=["x","y","width","height"];Object.values(t.attributes).filter(function(t){return i.includes(t.name)&&t.specified}).map(function(t){e.setAttribute(t.name,t.nodeValue)}),n&&e.setAttribute("transform",n)},dot:function(t,e){var n=void 0;"circle"!==t.nodeName&&(n=t.getAttribute("transform"),t=t.childNodes[0]);var i=["cx","cy"];Object.values(t.attributes).filter(function(t){return i.includes(t.name)&&t.specified}).map(function(t){e.setAttribute(t.name,t.nodeValue)}),n&&e.setAttribute("transform",n)},heat_square:function(t,e){var n=void 0;"circle"!==t.nodeName&&(n=t.getAttribute("transform"),t=t.childNodes[0]);var i=["cx","cy"];Object.values(t.attributes).filter(function(t){return i.includes(t.name)&&t.specified}).map(function(t){e.setAttribute(t.name,t.nodeValue)}),n&&e.setAttribute("transform",n)}},_slicedToArray$2=function(){function t(t,e){var n=[],i=!0,a=!1,r=void 0;try{for(var o,s=t[Symbol.iterator]();!(i=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);i=!0);}catch(t){a=!0,r=t}finally{try{!i&&s.return&&s.return()}finally{if(a)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),UNIT_ANIM_DUR=350,PATH_ANIM_DUR=350,MARKER_LINE_ANIM_DUR=UNIT_ANIM_DUR,REPLACE_ALL_NEW_DUR=250,STD_EASING="easein",_slicedToArray$1=function(){function t(t,e){var n=[],i=!0,a=!1,r=void 0;try{for(var o,s=t[Symbol.iterator]();!(i=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);i=!0);}catch(t){a=!0,r=t}finally{try{!i&&s.return&&s.return()}finally{if(a)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),EASING={ease:"0.25 0.1 0.25 1",linear:"0 0 1 1",easein:"0.1 0.8 0.2 1",easeout:"0 0 0.58 1",easeinout:"0.42 0 0.58 1"},CSSTEXT=".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}",_createClass$2=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]&&arguments[0],n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];e&&isHidden(this.parent)||(this.updateWidth(),this.calc(e),this.makeChartArea(),this.setupComponents(),this.components.forEach(function(e){return e.setup(t.drawArea)}),this.render(this.components,!1),n&&(this.data=this.realData,setTimeout(function(){t.update(t.data)},this.initTimeout)),this.renderLegend(),this.setupNavigation(n))}},{key:"calc",value:function(){}},{key:"updateWidth",value:function(){this.baseWidth=getElementContentWidth(this.parent),this.width=this.baseWidth-getExtraWidth(this.measures)}},{key:"makeChartArea",value:function(){this.svg&&this.container.removeChild(this.svg);var t=this.measures;this.svg=makeSVGContainer(this.container,"frappe-chart chart",this.baseWidth,this.baseHeight),this.svgDefs=makeSVGDefs(this.svg),this.title.length&&(this.titleEL=makeText("title",t.margins.left,t.margins.top,this.title,{fontSize:t.titleFontSize,fill:"#666666",dy:t.titleFontSize}));var e=getTopOffset(t);this.drawArea=makeSVGGroup(this.type+"-chart chart-draw-area","translate("+getLeftOffset(t)+", "+e+")"),this.config.showLegend&&(e+=this.height+t.paddings.bottom,this.legendArea=makeSVGGroup("chart-legend","translate("+getLeftOffset(t)+", "+e+")")),this.title.length&&this.svg.appendChild(this.titleEL),this.svg.appendChild(this.drawArea),this.config.showLegend&&this.svg.appendChild(this.legendArea),this.updateTipOffset(getLeftOffset(t),getTopOffset(t))}},{key:"updateTipOffset",value:function(t,e){this.tip.offset={x:t,y:e}}},{key:"setupComponents",value:function(){this.components=new Map}},{key:"update",value:function(t){t||console.error("No data to update."),this.data=this.prepareData(t),this.calc(),this.render(this.components,this.config.animate),this.renderLegend()}},{key:"render",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.components,n=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.config.isNavigable&&this.overlays.map(function(t){return t.parentNode.removeChild(t)});var i=[];e.forEach(function(t){i=i.concat(t.update(n))}),i.length>0?(runSMILAnimation(this.container,this.svg,i),setTimeout(function(){e.forEach(function(t){return t.make()}),t.updateNav()},CHART_POST_ANIMATE_TIMEOUT)):(e.forEach(function(t){return t.make()}),this.updateNav())}},{key:"updateNav",value:function(){this.config.isNavigable&&(this.makeOverlay(),this.bindUnits())}},{key:"renderLegend",value:function(){}},{key:"setupNavigation",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.config.isNavigable&&e&&(this.bindOverlay(),this.keyActions={13:this.onEnterKey.bind(this),37:this.onLeftArrow.bind(this),38:this.onUpArrow.bind(this),39:this.onRightArrow.bind(this),40:this.onDownArrow.bind(this)},document.addEventListener("keydown",function(e){isElementInViewport(t.container)&&(e=e||window.event,t.keyActions[e.keyCode]&&t.keyActions[e.keyCode]())}))}},{key:"makeOverlay",value:function(){}},{key:"updateOverlay",value:function(){}},{key:"bindOverlay",value:function(){}},{key:"bindUnits",value:function(){}},{key:"onLeftArrow",value:function(){}},{key:"onRightArrow",value:function(){}},{key:"onUpArrow",value:function(){}},{key:"onDownArrow",value:function(){}},{key:"onEnterKey",value:function(){}},{key:"addDataPoint",value:function(){}},{key:"removeDataPoint",value:function(){}},{key:"getDataPoint",value:function(){}},{key:"setCurrentDataPoint",value:function(){}},{key:"updateDataset",value:function(){}},{key:"export",value:function(){var t=prepareForExport(this.svg);downloadFile(this.title||"Chart",[t])}}]),t}(),_createClass$1=function(){function t(t,e){for(var n=0;n=0}),a=i;if(i.length>n){i.sort(function(t,e){return e[0]-t[0]}),a=i.slice(0,n-1);var r=0;i.slice(n-1).map(function(t){r+=t[0]}),a.push([r,"Rest"]),this.colors[n-1]="grey"}e.labels=[],a.map(function(t){e.sliceTotals.push(round(t[0])),e.labels.push(t[1])}),e.grandTotal=e.sliceTotals.reduce(function(t,e){return t+e},0),this.center={x:this.width/2,y:this.height/2}}},{key:"renderLegend",value:function(){var t=this,e=this.state;this.legendArea.textContent="",this.legendTotals=e.sliceTotals.slice(0,this.config.maxLegendPoints);var n=0,i=0;this.legendTotals.map(function(a,r){var o=150,s=Math.floor((t.width-getExtraWidth(t.measures))/o);t.legendTotals.lengths&&(n=0,i+=20);var l=o*n+5,u=t.config.truncateLegends?truncateString(e.labels[r],o/10):e.labels[r],c=t.config.formatTooltipY?t.config.formatTooltipY(a):a,h=legendDot(l,i,5,t.colors[r],u+": "+c,!1);t.legendArea.appendChild(h),n++})}}]),e}(BaseChart),NO_OF_YEAR_MONTHS=12,NO_OF_DAYS_IN_WEEK=7,NO_OF_MILLIS=1e3,SEC_IN_DAY=86400,MONTH_NAMES=["January","February","March","April","May","June","July","August","September","October","November","December"],DAY_NAMES_SHORT=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],_slicedToArray$3=function(){function t(t,e){var n=[],i=!0,a=!1,r=void 0;try{for(var o,s=t[Symbol.iterator]();!(i=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);i=!0);}catch(t){a=!0,r=t}finally{try{!i&&s.return&&s.return()}finally{if(a)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_createClass$4=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0])||arguments[0];this.refresh();var e=[];return t&&(e=this.animateElements(this.data)||[]),e}}]),t}(),componentConfigs={donutSlices:{layerClass:"donut-slices",makeElements:function(t){return t.sliceStrings.map(function(e,n){var i=makePath(e,"donut-path",t.colors[n],"none",t.strokeWidth);return i.style.transition="transform .3s;",i})},animateElements:function(t){return this.store.map(function(e,n){return animatePathStr(e,t.sliceStrings[n])})}},pieSlices:{layerClass:"pie-slices",makeElements:function(t){return t.sliceStrings.map(function(e,n){var i=makePath(e,"pie-path","none",t.colors[n]);return i.style.transition="transform .3s;",i})},animateElements:function(t){return this.store.map(function(e,n){return animatePathStr(e,t.sliceStrings[n])})}},percentageBars:{layerClass:"percentage-bars",makeElements:function(t){var e=this;return t.xPositions.map(function(n,i){return percentageBar(n,0,t.widths[i],e.constants.barHeight,e.constants.barDepth,t.colors[i])})},animateElements:function(t){if(t)return[]}},yAxis:{layerClass:"y axis",makeElements:function(t){var e=this;return t.positions.map(function(n,i){return yLine(n,t.labels[i],e.constants.width,{mode:e.constants.mode,pos:e.constants.pos,shortenNumbers:e.constants.shortenNumbers})})},animateElements:function(t){var e=t.positions,n=t.labels,i=this.oldData.positions,a=this.oldData.labels,r=equilizeNoOfElements(i,e),o=_slicedToArray$3(r,2);i=o[0],e=o[1];var s=equilizeNoOfElements(a,n),l=_slicedToArray$3(s,2);return a=l[0],n=l[1],this.render({positions:i,labels:n}),this.store.map(function(t,n){return translateHoriLine(t,e[n],i[n])})}},xAxis:{layerClass:"x axis",makeElements:function(t){var e=this;return t.positions.map(function(n,i){return xLine(n,t.calcLabels[i],e.constants.height,{mode:e.constants.mode,pos:e.constants.pos})})},animateElements:function(t){var e=t.positions,n=t.calcLabels,i=this.oldData.positions,a=this.oldData.calcLabels,r=equilizeNoOfElements(i,e),o=_slicedToArray$3(r,2);i=o[0],e=o[1];var s=equilizeNoOfElements(a,n),l=_slicedToArray$3(s,2);return a=l[0],n=l[1],this.render({positions:i,calcLabels:n}),this.store.map(function(t,n){return translateVertLine(t,e[n],i[n])})}},yMarkers:{layerClass:"y-markers",makeElements:function(t){var e=this;return t.map(function(t){return yMarker(t.position,t.label,e.constants.width,{labelPos:t.options.labelPos,mode:"span",lineType:"dashed"})})},animateElements:function(t){var e=equilizeNoOfElements(this.oldData,t),n=_slicedToArray$3(e,2);this.oldData=n[0];var i=(t=n[1]).map(function(t){return t.position}),a=t.map(function(t){return t.label}),r=t.map(function(t){return t.options}),o=this.oldData.map(function(t){return t.position});return this.render(o.map(function(t,e){return{position:o[e],label:a[e],options:r[e]}})),this.store.map(function(t,e){return translateHoriLine(t,i[e],o[e])})}},yRegions:{layerClass:"y-regions",makeElements:function(t){var e=this;return t.map(function(t){return yRegion(t.startPos,t.endPos,e.constants.width,t.label,{labelPos:t.options.labelPos})})},animateElements:function(t){var e=equilizeNoOfElements(this.oldData,t),n=_slicedToArray$3(e,2);this.oldData=n[0];var i=(t=n[1]).map(function(t){return t.endPos}),a=t.map(function(t){return t.label}),r=t.map(function(t){return t.startPos}),o=t.map(function(t){return t.options}),s=this.oldData.map(function(t){return t.endPos}),l=this.oldData.map(function(t){return t.startPos});this.render(s.map(function(t,e){return{startPos:l[e],endPos:s[e],label:a[e],options:o[e]}}));var u=[];return this.store.map(function(t,e){u=u.concat(animateRegion(t,r[e],i[e],s[e]))}),u}},heatDomain:{layerClass:function(){return"heat-domain domain-"+this.constants.index},makeElements:function(t){var e=this,n=this.constants,i=n.index,a=n.colWidth,r=n.rowHeight,o=n.squareSize,s=n.radius,l=n.xTranslate,u=0;return this.serializedSubDomains=[],t.cols.map(function(t,n){1===n&&e.labels.push(makeText("domain-name",l,-12,getMonthName(i,!0).toUpperCase(),{fontSize:9})),t.map(function(t,n){if(t.fill){var i={"data-date":t.yyyyMmDd,"data-value":t.dataValue,"data-day":n},a=heatSquare("day",l,u,o,s,t.fill,i);e.serializedSubDomains.push(a)}u+=r}),u=0,l+=a}),this.serializedSubDomains},animateElements:function(t){if(t)return[]}},barGraph:{layerClass:function(){return"dataset-units dataset-bars dataset-"+this.constants.index},makeElements:function(t){var e=this.constants;return this.unitType="bar",this.units=t.yPositions.map(function(n,i){return datasetBar(t.xPositions[i],n,t.barWidth,e.color,t.labels[i],i,t.offsets[i],{zeroLine:t.zeroLine,barsWidth:t.barsWidth,minHeight:e.minHeight})}),this.units},animateElements:function(t){var e=t.xPositions,n=t.yPositions,i=t.offsets,a=t.labels,r=this.oldData.xPositions,o=this.oldData.yPositions,s=this.oldData.offsets,l=this.oldData.labels,u=equilizeNoOfElements(r,e),c=_slicedToArray$3(u,2);r=c[0],e=c[1];var h=equilizeNoOfElements(o,n),d=_slicedToArray$3(h,2);o=d[0],n=d[1];var f=equilizeNoOfElements(s,i),p=_slicedToArray$3(f,2);s=p[0],i=p[1];var v=equilizeNoOfElements(l,a),g=_slicedToArray$3(v,2);l=g[0],a=g[1],this.render({xPositions:r,yPositions:o,offsets:s,labels:a,zeroLine:this.oldData.zeroLine,barsWidth:this.oldData.barsWidth,barWidth:this.oldData.barWidth});var y=[];return this.store.map(function(a,r){y=y.concat(animateBar(a,e[r],n[r],t.barWidth,i[r],{zeroLine:t.zeroLine}))}),y}},lineGraph:{layerClass:function(){return"dataset-units dataset-line dataset-"+this.constants.index},makeElements:function(t){var e=this.constants;return this.unitType="dot",this.paths={},e.hideLine||(this.paths=getPaths(t.xPositions,t.yPositions,e.color,{heatline:e.heatline,regionFill:e.regionFill,spline:e.spline},{svgDefs:e.svgDefs,zeroLine:t.zeroLine})),this.units=[],e.hideDots||(this.units=t.yPositions.map(function(n,i){return datasetDot(t.xPositions[i],n,t.radius,e.color,e.valuesOverPoints?t.values[i]:"",i)})),Object.values(this.paths).concat(this.units)},animateElements:function(t){var e=t.xPositions,n=t.yPositions,i=t.values,a=this.oldData.xPositions,r=this.oldData.yPositions,o=this.oldData.values,s=equilizeNoOfElements(a,e),l=_slicedToArray$3(s,2);a=l[0],e=l[1];var u=equilizeNoOfElements(r,n),c=_slicedToArray$3(u,2);r=c[0],n=c[1];var h=equilizeNoOfElements(o,i),d=_slicedToArray$3(h,2);o=d[0],i=d[1],this.render({xPositions:a,yPositions:r,values:i,zeroLine:this.oldData.zeroLine,radius:this.oldData.radius});var f=[];return Object.keys(this.paths).length&&(f=f.concat(animatePath(this.paths,e,n,t.zeroLine,this.constants.spline))),this.units.length&&this.units.map(function(t,i){f=f.concat(animateDot(t,e[i],n[i]))}),f}}},_createClass=function(){function t(t,e){for(var n=0;n0?t.formattedLabels[r]:t.state.labels[r])+": ",h=e.sliceTotals[r]/e.grandTotal;t.tip.setValues(l,u,{name:c,value:(100*h).toFixed(1)+"%"}),t.tip.showTip()}})}}]),e}(AggregationChart),_createClass$5=function(){function t(t,e){for(var n=0;nthis.width?this.center.x:this.center.y;var i=this.radius,a=this.clockWise,r=n.slicesProperties||[];n.sliceStrings=[],n.slicesProperties=[];var o=180-this.config.startAngle;n.sliceTotals.map(function(e,s){var l=o,u=e/n.grandTotal*FULL_ANGLE,c=u>180?1:0,h=a?-u:u,d=o+=h,f=getPositionByAngle(l,i),p=getPositionByAngle(d,i),v=t.init&&r[s],g=void 0,y=void 0;t.init?(g=v?v.startPosition:f,y=v?v.endPosition:f):(g=f,y=p);var m=360===u?makeCircleStr(g,y,t.center,t.radius,a,c):makeArcPathStr(g,y,t.center,t.radius,a,c);n.sliceStrings.push(m),n.slicesProperties.push({startPosition:f,endPosition:p,value:e,total:n.grandTotal,startAngle:l,endAngle:d,angle:h})}),this.init=0}},{key:"setupComponents",value:function(){var t=this.state,e=[["pieSlices",{},function(){return{sliceStrings:t.sliceStrings,colors:this.colors}}.bind(this)]];this.components=new Map(e.map(function(t){var e=getComponent.apply(void 0,_toConsumableArray$2(t));return[t[0],e]}))}},{key:"calTranslateByAngle",value:function(t){var e=this.radius,n=this.hoverRadio,i=getPositionByAngle(t.startAngle+t.angle/2,e);return"translate3d("+i.x*n+"px,"+i.y*n+"px,0)"}},{key:"hoverSlice",value:function(t,e,n,i){if(t){var a=this.colors[e];if(n){transform(t,this.calTranslateByAngle(this.state.slicesProperties[e])),t.style.fill=lightenDarkenColor(a,50);var r=getOffset(this.svg),o=i.pageX-r.left+10,s=i.pageY-r.top-10,l=(this.formatted_labels&&this.formatted_labels.length>0?this.formatted_labels[e]:this.state.labels[e])+": ",u=(100*this.state.sliceTotals[e]/this.state.grandTotal).toFixed(1);this.tip.setValues(o,s,{name:l,value:u+"%"}),this.tip.showTip()}else transform(t,"translate3d(0,0,0)"),this.tip.hideTip(),t.style.fill=a}}},{key:"bindTooltip",value:function(){this.container.addEventListener("mousemove",this.mouseMove),this.container.addEventListener("mouseleave",this.mouseLeave)}},{key:"mouseMove",value:function(t){var e=t.target,n=this.components.get("pieSlices").store,i=this.curActiveSliceIndex,a=this.curActiveSlice;if(n.includes(e)){var r=n.indexOf(e);this.hoverSlice(a,i,!1),this.curActiveSlice=e,this.curActiveSliceIndex=r,this.hoverSlice(e,r,!0,t)}else this.mouseLeave()}},{key:"mouseLeave",value:function(){this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,!1)}}]),e}(AggregationChart),_slicedToArray$4=function(){function t(t,e){var n=[],i=!0,a=!1,r=void 0;try{for(var o,s=t[Symbol.iterator]();!(i=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);i=!0);}catch(t){a=!0,r=t}finally{try{!i&&s.return&&s.return()}finally{if(a)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_createClass$6=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:this.data;if(t.start&&t.end&&t.start>t.end)throw new Error("Start date cannot be greater than end date.");if(t.start||(t.start=new Date,t.start.setFullYear(t.start.getFullYear()-1)),t.end||(t.end=new Date),t.dataPoints=t.dataPoints||{},parseInt(Object.keys(t.dataPoints)[0])>1e5){var e={};Object.keys(t.dataPoints).forEach(function(n){var i=new Date(n*NO_OF_MILLIS);e[getYyyyMmDd(i)]=t.dataPoints[n]}),t.dataPoints=e}return t}},{key:"calc",value:function(){var t=this.state;t.start=clone(this.data.start),t.end=clone(this.data.end),t.firstWeekStart=clone(t.start),t.noOfWeeks=getWeeksBetween(t.start,t.end),t.distribution=calcDistribution(Object.values(this.data.dataPoints),HEATMAP_DISTRIBUTION_SIZE),t.domainConfigs=this.getDomains()}},{key:"setupComponents",value:function(){var t=this,e=this.state,n=this.discreteDomains?0:1,i=e.domainConfigs.map(function(i,a){return["heatDomain",{index:i.index,colWidth:COL_WIDTH,rowHeight:ROW_HEIGHT,squareSize:HEATMAP_SQUARE_SIZE,radius:t.rawChartArgs.radius||0,xTranslate:e.domainConfigs.filter(function(t,e){return e1&&void 0!==arguments[1]?arguments[1]:"",n=[t.getMonth(),t.getFullYear()],i=n[0],a=n[1],r=setDayToSunday(t),o={index:i,cols:[]};addDays(e=clone(e)||getLastDateInMonth(i,a),1);for(var s=getWeeksBetween(r,e),l=[],u=void 0,c=0;c2&&void 0!==arguments[2]&&arguments[2],i=this.state,a=clone(t),r=[],o=0;o=i.start&&a<=i.end;n||a.getMonth()!==e||!l?s.yyyyMmDd=getYyyyMmDd(a):s=this.getSubDomainConfig(a),r.push(s)}return r}},{key:"getSubDomainConfig",value:function(t){var e=getYyyyMmDd(t),n=this.data.dataPoints[e];return{yyyyMmDd:e,dataValue:n||0,fill:this.colors[getMaxCheckpoint(n,this.state.distribution)]}}}]),e}(BaseChart),_createClass$7=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:this.data,this.type)}},{key:"prepareFirstData",value:function(){return zeroDataPrep(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.data)}},{key:"calc",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.calcXPositions(),t||this.calcYAxisParameters(this.getAllYValues(),"line"===this.type),this.makeDataByIndex()}},{key:"calcXPositions",value:function(){var t=this.state,e=this.data.labels;t.datasetLength=e.length,t.unitWidth=this.width/t.datasetLength,t.xOffset=t.unitWidth/2,t.xAxis={labels:e,positions:e.map(function(e,n){return floatTwo(t.xOffset+n*t.unitWidth)})}}},{key:"calcYAxisParameters",value:function(t){var e=calcChartIntervals(t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:"false"),n=this.height/getValueRange(e),i=getIntervalSize(e)*n,a=this.height-getZeroIndex(e)*i;this.state.yAxis={labels:e,positions:e.map(function(t){return a-t*n}),scaleMultiplier:n,zeroLine:a},this.calcDatasetPoints(),this.calcYExtremes(),this.calcYRegions()}},{key:"calcDatasetPoints",value:function(){var t=this.state,e=function(e){return e.map(function(e){return scale(e,t.yAxis)})};t.datasets=this.data.datasets.map(function(t,n){var i=t.values,a=t.cumulativeYs||[];return{name:t.name&&t.name.replace(/<|>|&/g,function(t){return"&"==t?"&":"<"==t?"<":">"}),index:n,chartType:t.chartType,values:i,yPositions:e(i),cumulativeYs:a,cumulativeYPos:e(a)}})}},{key:"calcYExtremes",value:function(){var t=this.state;if(this.barOptions.stacked)return void(t.yExtremes=t.datasets[t.datasets.length-1].cumulativeYPos);t.yExtremes=new Array(t.datasetLength).fill(9999),t.datasets.map(function(e){e.yPositions.map(function(e,n){egetTopOffset(n)?t.mapTooltipXPosition(a):t.tip.hideTip()})}},{key:"mapTooltipXPosition",value:function(t){var e=this.state;if(e.yExtremes){var n=getClosestInArray(t,e.xAxis.positions,!0);if(n>=0){var i=this.dataByIndex[n];this.tip.setValues(i.xPos+this.tip.offset.x,i.yExtreme+this.tip.offset.y,{name:i.formattedLabel,value:""},i.values,n),this.tip.showTip()}}}},{key:"renderLegend",value:function(){var t=this,e=this.data;e.datasets.length>1&&(this.legendArea.textContent="",e.datasets.map(function(e,n){var i=AXIS_LEGEND_BAR_SIZE,a=legendBar(i*n,"0",i,t.colors[n],e.name,t.config.truncateLegends);t.legendArea.appendChild(a)}))}},{key:"makeOverlay",value:function(){var t=this;if(this.init)return void(this.init=0);this.overlayGuides&&this.overlayGuides.forEach(function(t){var e=t.overlay;e.parentNode.removeChild(e)}),this.overlayGuides=this.dataUnitComponents.map(function(t){return{type:t.unitType,overlay:void 0,units:t.units}}),void 0===this.state.currentIndex&&(this.state.currentIndex=this.state.datasetLength-1),this.overlayGuides.map(function(e){var n=e.units[t.state.currentIndex];e.overlay=makeOverlay[e.type](n),t.drawArea.appendChild(e.overlay)})}},{key:"updateOverlayGuides",value:function(){this.overlayGuides&&this.overlayGuides.forEach(function(t){var e=t.overlay;e.parentNode.removeChild(e)})}},{key:"bindOverlay",value:function(){var t=this;this.parent.addEventListener("data-select",function(){t.updateOverlay()})}},{key:"bindUnits",value:function(){var t=this;this.dataUnitComponents.map(function(e){e.units.map(function(e){e.addEventListener("click",function(){var n=e.getAttribute("data-point-index");t.setCurrentDataPoint(n)})})}),this.tip.container.addEventListener("click",function(){var e=t.tip.container.getAttribute("data-point-index");t.setCurrentDataPoint(e)})}},{key:"updateOverlay",value:function(){var t=this;this.overlayGuides.map(function(e){var n=e.units[t.state.currentIndex];updateOverlay[e.type](n,e.overlay)})}},{key:"onLeftArrow",value:function(){this.setCurrentDataPoint(this.state.currentIndex-1)}},{key:"onRightArrow",value:function(){this.setCurrentDataPoint(this.state.currentIndex+1)}},{key:"getDataPoint",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.state.currentIndex,e=this.state;return{index:t,label:e.xAxis.labels[t],values:e.datasets.map(function(e){return e.values[t]})}}},{key:"setCurrentDataPoint",value:function(t){var e=this.state;(t=parseInt(t))<0&&(t=0),t>=e.xAxis.labels.length&&(t=e.xAxis.labels.length-1),t!==e.currentIndex&&(e.currentIndex=t,fire(this.parent,"data-select",this.getDataPoint()))}},{key:"addDataPoint",value:function(t,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.state.datasetLength;_get$3(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"addDataPoint",this).call(this,t,n,i),this.data.labels.splice(i,0,t),this.data.datasets.map(function(t,e){t.values.splice(i,0,n[e])}),this.update(this.data)}},{key:"removeDataPoint",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.state.datasetLength-1;this.data.labels.length<=1||(_get$3(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"removeDataPoint",this).call(this,t),this.data.labels.splice(t,1),this.data.datasets.map(function(e){e.values.splice(t,1)}),this.update(this.data))}},{key:"updateDataset",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;this.data.datasets[e].values=t,this.update(this.data)}},{key:"updateDatasets",value:function(t){this.data.datasets.map(function(e,n){t[n]&&(e.values=t[n])}),this.update(this.data)}}]),e}(BaseChart),_createClass$8=function(){function t(t,e){for(var n=0;nthis.width?this.center.x-this.strokeWidth/2:this.center.y-this.strokeWidth/2;var i=this.radius,a=this.clockWise,r=n.slicesProperties||[];n.sliceStrings=[],n.slicesProperties=[];var o=180-this.config.startAngle;n.sliceTotals.map(function(e,s){var l=o,u=e/n.grandTotal*FULL_ANGLE,c=u>180?1:0,h=a?-u:u,d=o+=h,f=getPositionByAngle(l,i),p=getPositionByAngle(d,i),v=t.init&&r[s],g=void 0,y=void 0;t.init?(g=v?v.startPosition:f,y=v?v.endPosition:f):(g=f,y=p);var m=360===u?makeStrokeCircleStr(g,y,t.center,t.radius,t.clockWise,c):makeArcStrokePathStr(g,y,t.center,t.radius,t.clockWise,c);n.sliceStrings.push(m),n.slicesProperties.push({startPosition:f,endPosition:p,value:e,total:n.grandTotal,startAngle:l,endAngle:d,angle:h})}),this.init=0}},{key:"setupComponents",value:function(){var t=this.state,e=[["donutSlices",{},function(){return{sliceStrings:t.sliceStrings,colors:this.colors,strokeWidth:this.strokeWidth}}.bind(this)]];this.components=new Map(e.map(function(t){var e=getComponent.apply(void 0,_toConsumableArray$7(t));return[t[0],e]}))}},{key:"calTranslateByAngle",value:function(t){var e=this.radius,n=this.hoverRadio,i=getPositionByAngle(t.startAngle+t.angle/2,e);return"translate3d("+i.x*n+"px,"+i.y*n+"px,0)"}},{key:"hoverSlice",value:function(t,e,n,i){if(t){var a=this.colors[e];if(n){transform(t,this.calTranslateByAngle(this.state.slicesProperties[e])),t.style.stroke=lightenDarkenColor(a,50);var r=getOffset(this.svg),o=i.pageX-r.left+10,s=i.pageY-r.top-10,l=(this.formatted_labels&&this.formatted_labels.length>0?this.formatted_labels[e]:this.state.labels[e])+": ",u=(100*this.state.sliceTotals[e]/this.state.grandTotal).toFixed(1);this.tip.setValues(o,s,{name:l,value:u+"%"}),this.tip.showTip()}else transform(t,"translate3d(0,0,0)"),this.tip.hideTip(),t.style.stroke=a}}},{key:"bindTooltip",value:function(){this.container.addEventListener("mousemove",this.mouseMove),this.container.addEventListener("mouseleave",this.mouseLeave)}},{key:"mouseMove",value:function(t){var e=t.target,n=this.components.get("donutSlices").store,i=this.curActiveSliceIndex,a=this.curActiveSlice;if(n.includes(e)){var r=n.indexOf(e);this.hoverSlice(a,i,!1),this.curActiveSlice=e,this.curActiveSliceIndex=r,this.hoverSlice(e,r,!0,t)}else this.mouseLeave()}},{key:"mouseLeave",value:function(){this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,!1)}}]),e}(AggregationChart),chartTypes={bar:AxisChart,line:AxisChart,percentage:PercentageChart,heatmap:Heatmap,pie:PieChart,donut:DonutChart},Chart=function t(e,n){return _classCallCheck(this,t),getChartByType(n.type,e,n)};exports.Chart=Chart,exports.PercentageChart=PercentageChart,exports.PieChart=PieChart,exports.Heatmap=Heatmap,exports.AxisChart=AxisChart; -//# sourceMappingURL=frappe-charts.min.cjs.js.map diff --git a/node_modules/frappe-charts/dist/frappe-charts.min.cjs.js.map b/node_modules/frappe-charts/dist/frappe-charts.min.cjs.js.map deleted file mode 100644 index 1e9a986..0000000 --- a/node_modules/frappe-charts/dist/frappe-charts.min.cjs.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"frappe-charts.min.cjs.js","sources":["../node_modules/style-inject/dist/style-inject.es.js","../src/js/utils/dom.js","../src/js/utils/constants.js","../src/js/utils/helpers.js","../src/js/utils/draw-utils.js","../src/js/utils/colors.js","../src/js/utils/draw.js","../src/js/utils/animate.js","../src/js/utils/animation.js","../src/js/utils/export.js","../src/js/utils/date-utils.js","../src/js/objects/ChartComponents.js","../src/js/utils/intervals.js","../src/js/utils/axis-chart-utils.js","../src/js/chart.js","../src/js/objects/SvgTip.js","../src/css/chartsCss.js","../src/js/charts/BaseChart.js","../src/js/charts/AggregationChart.js","../src/js/charts/PercentageChart.js","../src/js/charts/PieChart.js","../src/js/charts/Heatmap.js","../src/js/charts/AxisChart.js","../src/js/charts/DonutChart.js"],"sourcesContent":["function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","export function $(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\nexport function findNodeIndex(node)\n{\n\tvar i = 0;\n\twhile (node.previousSibling) {\n\t\tnode = node.previousSibling;\n\t\ti++;\n\t}\n\treturn i;\n}\n\n$.create = (tag, o) => {\n\tvar element = document.createElement(tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (i in element ) {\n\t\t\telement[i] = val;\n\t\t}\n\t\telse {\n\t\t\telement.setAttribute(i, val);\n\t\t}\n\t}\n\n\treturn element;\n};\n\nexport function getOffset(element) {\n\tlet rect = element.getBoundingClientRect();\n\treturn {\n\t\t// https://stackoverflow.com/a/7436602/6495043\n\t\t// rect.top varies with scroll, so we add whatever has been\n\t\t// scrolled to it to get absolute distance from actual page top\n\t\ttop: rect.top + (document.documentElement.scrollTop || document.body.scrollTop),\n\t\tleft: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft)\n\t};\n}\n\n// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent\n// an element's offsetParent property will return null whenever it, or any of its parents,\n// is hidden via the display style property.\nexport function isHidden(el) {\n\treturn (el.offsetParent === null);\n}\n\nexport function isElementInViewport(el) {\n\t// Although straightforward: https://stackoverflow.com/a/7557433/6495043\n\tvar rect = el.getBoundingClientRect();\n\n\treturn (\n\t\trect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */\n rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */\n\t);\n}\n\nexport function getElementContentWidth(element) {\n\tvar styles = window.getComputedStyle(element);\n\tvar padding = parseFloat(styles.paddingLeft) +\n\t\tparseFloat(styles.paddingRight);\n\n\treturn element.clientWidth - padding;\n}\n\nexport function bind(element, o){\n\tif (element) {\n\t\tfor (var event in o) {\n\t\t\tvar callback = o[event];\n\n\t\t\tevent.split(/\\s+/).forEach(function (event) {\n\t\t\t\telement.addEventListener(event, callback);\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport function unbind(element, o){\n\tif (element) {\n\t\tfor (var event in o) {\n\t\t\tvar callback = o[event];\n\n\t\t\tevent.split(/\\s+/).forEach(function(event) {\n\t\t\t\telement.removeEventListener(event, callback);\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport function fire(target, type, properties) {\n\tvar evt = document.createEvent(\"HTMLEvents\");\n\n\tevt.initEvent(type, true, true );\n\n\tfor (var j in properties) {\n\t\tevt[j] = properties[j];\n\t}\n\n\treturn target.dispatchEvent(evt);\n}\n\n// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/\nexport function forEachNode(nodeList, callback, scope) {\n\tif(!nodeList) return;\n\tfor (var i = 0; i < nodeList.length; i++) {\n\t\tcallback.call(scope, nodeList[i], i);\n\t}\n}\n\nexport function activate($parent, $child, commonClass, activeClass='active', index = -1) {\n\tlet $children = $parent.querySelectorAll(`.${commonClass}.${activeClass}`);\n\n\tforEachNode($children, (node, i) => {\n\t\tif(index >= 0 && i <= index) return;\n\t\tnode.classList.remove(activeClass);\n\t});\n\n\t$child.classList.add(activeClass);\n}\n","export const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];\n\nexport const COMPATIBLE_CHARTS = {\n\tbar: ['line', 'scatter', 'percentage', 'pie'],\n\tline: ['scatter', 'bar', 'percentage', 'pie'],\n\tpie: ['line', 'scatter', 'percentage', 'bar'],\n\tpercentage: ['bar', 'line', 'scatter', 'pie'],\n\theatmap: []\n};\n\nexport const DATA_COLOR_DIVISIONS = {\n\tbar: 'datasets',\n\tline: 'datasets',\n\tpie: 'labels',\n\tpercentage: 'labels',\n\theatmap: HEATMAP_DISTRIBUTION_SIZE\n};\n\nexport const BASE_MEASURES = {\n\tmargins: {\n\t\ttop: 10,\n\t\tbottom: 10,\n\t\tleft: 20,\n\t\tright: 20\n\t},\n\tpaddings: {\n\t\ttop: 20,\n\t\tbottom: 40,\n\t\tleft: 30,\n\t\tright: 10\n\t},\n\n\tbaseHeight: 240,\n\ttitleHeight: 20,\n\tlegendHeight: 30,\n\n\ttitleFontSize: 12,\n};\n\nexport function getTopOffset(m) {\n\treturn m.titleHeight + m.margins.top + m.paddings.top;\n}\n\nexport function getLeftOffset(m) {\n\treturn m.margins.left + m.paddings.left;\n}\n\nexport function getExtraHeight(m) {\n\tlet totalExtraHeight = m.margins.top + m.margins.bottom\n\t\t+ m.paddings.top + m.paddings.bottom\n\t\t+ m.titleHeight + m.legendHeight;\n\treturn totalExtraHeight;\n}\n\nexport function getExtraWidth(m) {\n\tlet totalExtraWidth = m.margins.left + m.margins.right\n\t\t+ m.paddings.left + m.paddings.right;\n\n\treturn totalExtraWidth;\n}\n\nexport const INIT_CHART_UPDATE_TIMEOUT = 700;\nexport const CHART_POST_ANIMATE_TIMEOUT = 400;\n\nexport const DEFAULT_AXIS_CHART_TYPE = 'line';\nexport const AXIS_DATASET_CHART_TYPES = ['line', 'bar'];\n\nexport const AXIS_LEGEND_BAR_SIZE = 100;\n\nexport const BAR_CHART_SPACE_RATIO = 0.5;\nexport const MIN_BAR_PERCENT_HEIGHT = 0.00;\n\nexport const LINE_CHART_DOT_SIZE = 4;\nexport const DOT_OVERLAY_SIZE_INCR = 4;\n\nexport const PERCENTAGE_BAR_DEFAULT_HEIGHT = 20;\nexport const PERCENTAGE_BAR_DEFAULT_DEPTH = 2;\n\n// Fixed 5-color theme,\n// More colors are difficult to parse visually\nexport const HEATMAP_DISTRIBUTION_SIZE = 5;\n\nexport const HEATMAP_SQUARE_SIZE = 10;\nexport const HEATMAP_GUTTER_SIZE = 2;\n\nexport const DEFAULT_CHAR_WIDTH = 7;\n\nexport const TOOLTIP_POINTER_TRIANGLE_HEIGHT = 5;\n\nconst DEFAULT_CHART_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',\n\t'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey'];\nconst HEATMAP_COLORS_GREEN = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];\nexport const HEATMAP_COLORS_BLUE = ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'];\nexport const HEATMAP_COLORS_YELLOW = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];\n\nexport const DEFAULT_COLORS = {\n\tbar: DEFAULT_CHART_COLORS,\n\tline: DEFAULT_CHART_COLORS,\n\tpie: DEFAULT_CHART_COLORS,\n\tpercentage: DEFAULT_CHART_COLORS,\n\theatmap: HEATMAP_COLORS_GREEN,\n\tdonut: DEFAULT_CHART_COLORS\n};\n\n// Universal constants\nexport const ANGLE_RATIO = Math.PI / 180;\nexport const FULL_ANGLE = 360;\n","import { ANGLE_RATIO } from './constants';\n\n/**\n * Returns the value of a number upto 2 decimal places.\n * @param {Number} d Any number\n */\nexport function floatTwo(d) {\n\treturn parseFloat(d.toFixed(2));\n}\n\n/**\n * Returns whether or not two given arrays are equal.\n * @param {Array} arr1 First array\n * @param {Array} arr2 Second array\n */\nexport function arraysEqual(arr1, arr2) {\n\tif(arr1.length !== arr2.length) return false;\n\tlet areEqual = true;\n\tarr1.map((d, i) => {\n\t\tif(arr2[i] !== d) areEqual = false;\n\t});\n\treturn areEqual;\n}\n\n/**\n * Shuffles array in place. ES6 version\n * @param {Array} array An array containing the items.\n */\nexport function shuffle(array) {\n\t// Awesomeness: https://bost.ocks.org/mike/shuffle/\n\t// https://stackoverflow.com/a/2450976/6495043\n\t// https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array?noredirect=1&lq=1\n\n\tfor (let i = array.length - 1; i > 0; i--) {\n\t\tlet j = Math.floor(Math.random() * (i + 1));\n\t\t[array[i], array[j]] = [array[j], array[i]];\n\t}\n\n\treturn array;\n}\n\n/**\n * Fill an array with extra points\n * @param {Array} array Array\n * @param {Number} count number of filler elements\n * @param {Object} element element to fill with\n * @param {Boolean} start fill at start?\n */\nexport function fillArray(array, count, element, start=false) {\n\tif(!element) {\n\t\telement = start ? array[0] : array[array.length - 1];\n\t}\n\tlet fillerArray = new Array(Math.abs(count)).fill(element);\n\tarray = start ? fillerArray.concat(array) : array.concat(fillerArray);\n\treturn array;\n}\n\n/**\n * Returns pixel width of string.\n * @param {String} string\n * @param {Number} charWidth Width of single char in pixels\n */\nexport function getStringWidth(string, charWidth) {\n\treturn (string+\"\").length * charWidth;\n}\n\nexport function bindChange(obj, getFn, setFn) {\n\treturn new Proxy(obj, {\n\t\tset: function(target, prop, value) {\n\t\t\tsetFn();\n\t\t\treturn Reflect.set(target, prop, value);\n\t\t},\n\t\tget: function(target, prop) {\n\t\t\tgetFn();\n\t\t\treturn Reflect.get(target, prop);\n\t\t}\n\t});\n}\n\n// https://stackoverflow.com/a/29325222\nexport function getRandomBias(min, max, bias, influence) {\n\tconst range = max - min;\n\tconst biasValue = range * bias + min;\n\tvar rnd = Math.random() * range + min,\t\t// random in range\n\t\tmix = Math.random() * influence;\t\t// random mixer\n\treturn rnd * (1 - mix) + biasValue * mix;\t// mix full range and bias\n}\n\nexport function getPositionByAngle(angle, radius) {\n\treturn {\n\t\tx: Math.sin(angle * ANGLE_RATIO) * radius,\n\t\ty: Math.cos(angle * ANGLE_RATIO) * radius,\n\t};\n}\n\n/**\n * Check if a number is valid for svg attributes\n * @param {object} candidate Candidate to test\n * @param {Boolean} nonNegative flag to treat negative number as invalid\n */\nexport function isValidNumber(candidate, nonNegative=false) {\n\tif (Number.isNaN(candidate)) return false;\n\telse if (candidate === undefined) return false;\n\telse if (!Number.isFinite(candidate)) return false;\n\telse if (nonNegative && candidate < 0) return false;\n\telse return true;\n}\n\n/**\n * Round a number to the closes precision, max max precision 4\n * @param {Number} d Any Number\n */\nexport function round(d) {\n\t// https://floating-point-gui.de/\n\t// https://www.jacklmoore.com/notes/rounding-in-javascript/\n\treturn Number(Math.round(d + 'e4') + 'e-4');\n}\n\n/**\n * Creates a deep clone of an object\n * @param {Object} candidate Any Object\n */\n export function deepClone(candidate) {\n\tlet cloned, value, key;\n \n\tif (candidate instanceof Date) {\n\t return new Date(candidate.getTime());\n\t}\n \n\tif (typeof candidate !== \"object\" || candidate === null) {\n\t return candidate;\n\t}\n \n\tcloned = Array.isArray(candidate) ? [] : {};\n \n\tfor (key in candidate) {\n\t value = candidate[key];\n \n\t cloned[key] = deepClone(value);\n\t}\n \n\treturn cloned;\n }","import { fillArray } from './helpers';\n\nexport function getBarHeightAndYAttr(yTop, zeroLine) {\n\tlet height, y;\n\tif (yTop <= zeroLine) {\n\t\theight = zeroLine - yTop;\n\t\ty = yTop;\n\t} else {\n\t\theight = yTop - zeroLine;\n\t\ty = zeroLine;\n\t}\n\n\treturn [height, y];\n}\n\nexport function equilizeNoOfElements(array1, array2,\n\textraCount = array2.length - array1.length) {\n\n\t// Doesn't work if either has zero elements.\n\tif(extraCount > 0) {\n\t\tarray1 = fillArray(array1, extraCount);\n\t} else {\n\t\tarray2 = fillArray(array2, extraCount);\n\t}\n\treturn [array1, array2];\n}\n\nexport function truncateString(txt, len) {\n\tif (!txt) {\n\t\treturn;\n\t}\n\tif (txt.length > len) {\n\t\treturn txt.slice(0, len-3) + '...';\n\t} else {\n\t\treturn txt;\n\t}\n}\n\nexport function shortenLargeNumber(label) {\n\tlet number;\n\tif (typeof label === 'number') number = label;\n\telse if (typeof label === 'string') {\n\t\tnumber = Number(label);\n\t\tif (Number.isNaN(number)) return label;\n\t}\n\n\t// Using absolute since log wont work for negative numbers\n\tlet p = Math.floor(Math.log10(Math.abs(number)));\n\tif (p <= 2) return number; // Return as is for a 3 digit number of less\n\tlet\tl = Math.floor(p / 3);\n\tlet shortened = (Math.pow(10, p - l * 3) * +(number / Math.pow(10, p)).toFixed(1));\n\n\t// Correct for floating point error upto 2 decimal places\n\treturn Math.round(shortened*100)/100 + ' ' + ['', 'K', 'M', 'B', 'T'][l];\n}\n\n// cubic bezier curve calculation (from example by François Romain)\nexport function getSplineCurvePointsStr(xList, yList) {\n\n\tlet points=[];\n\tfor(let i=0;i {\n\t\tlet lengthX = pointB[0] - pointA[0];\n\t\tlet lengthY = pointB[1] - pointA[1];\n\t\treturn {\n\t\t\tlength: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),\n\t\t\tangle: Math.atan2(lengthY, lengthX)\n\t\t};\n\t};\n \n\tlet controlPoint = (current, previous, next, reverse) => {\n\t\tlet p = previous || current;\n\t\tlet n = next || current;\n\t\tlet o = line(p, n);\n\t\tlet angle = o.angle + (reverse ? Math.PI : 0);\n\t\tlet length = o.length * smoothing;\n\t\tlet x = current[0] + Math.cos(angle) * length;\n\t\tlet y = current[1] + Math.sin(angle) * length;\n\t\treturn [x, y];\n\t};\n \n\tlet bezierCommand = (point, i, a) => {\n\t\tlet cps = controlPoint(a[i - 1], a[i - 2], point);\n\t\tlet cpe = controlPoint(point, a[i - 1], a[i + 1], true);\n\t\treturn `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`;\n\t};\n \n\tlet pointStr = (points, command) => {\n\t\treturn points.reduce((acc, point, i, a) => i === 0\n\t\t\t? `${point[0]},${point[1]}`\n\t\t\t: `${acc} ${command(point, i, a)}`, '');\n\t};\n \n\treturn pointStr(points, bezierCommand);\n}\n","const PRESET_COLOR_MAP = {\n\t'light-blue': '#7cd6fd',\n\t'blue': '#5e64ff',\n\t'violet': '#743ee2',\n\t'red': '#ff5858',\n\t'orange': '#ffa00a',\n\t'yellow': '#feef72',\n\t'green': '#28a745',\n\t'light-green': '#98d85b',\n\t'purple': '#b554ff',\n\t'magenta': '#ffa3ef',\n\t'black': '#36114C',\n\t'grey': '#bdd3e6',\n\t'light-grey': '#f0f4f7',\n\t'dark-grey': '#b8c2cc'\n};\n\nfunction limitColor(r){\n\tif (r > 255) return 255;\n\telse if (r < 0) return 0;\n\treturn r;\n}\n\nexport function lightenDarkenColor(color, amt) {\n\tlet col = getColor(color);\n\tlet usePound = false;\n\tif (col[0] == \"#\") {\n\t\tcol = col.slice(1);\n\t\tusePound = true;\n\t}\n\tlet num = parseInt(col,16);\n\tlet r = limitColor((num >> 16) + amt);\n\tlet b = limitColor(((num >> 8) & 0x00FF) + amt);\n\tlet g = limitColor((num & 0x0000FF) + amt);\n\treturn (usePound?\"#\":\"\") + (g | (b << 8) | (r << 16)).toString(16);\n}\n\nexport function isValidColor(string) {\n\t// https://stackoverflow.com/a/32685393\n\tlet HEX_RE = /(^\\s*)(#)((?:[A-Fa-f0-9]{3}){1,2})$/i;\n\tlet RGB_RE = /(^\\s*)(rgb|hsl)(a?)[(]\\s*([\\d.]+\\s*%?)\\s*,\\s*([\\d.]+\\s*%?)\\s*,\\s*([\\d.]+\\s*%?)\\s*(?:,\\s*([\\d.]+)\\s*)?[)]$/i;\n\treturn HEX_RE.test(string) || RGB_RE.test(string);\n}\n\nexport const getColor = (color) => {\n\t// When RGB color, convert to hexadecimal (alpha value is omitted)\n\tif((/rgb[a]{0,1}\\([\\d, ]+\\)/gim).test(color)) {\n\t\treturn (/\\D+(\\d*)\\D+(\\d*)\\D+(\\d*)/gim).exec(color)\n\t\t\t.map((x, i) => (i !== 0 ? Number(x).toString(16) : '#'))\n\t\t\t.reduce((c, ch) => `${c}${ch}`);\n\t}\n\treturn PRESET_COLOR_MAP[color] || color;\n};\n","import { getBarHeightAndYAttr, truncateString, shortenLargeNumber, getSplineCurvePointsStr } from './draw-utils';\nimport { getStringWidth, isValidNumber } from './helpers';\nimport { DOT_OVERLAY_SIZE_INCR, PERCENTAGE_BAR_DEFAULT_DEPTH } from './constants';\nimport { lightenDarkenColor } from './colors';\n\nexport const AXIS_TICK_LENGTH = 6;\nconst LABEL_MARGIN = 4;\nconst LABEL_MAX_CHARS = 15;\nexport const FONT_SIZE = 10;\nconst BASE_LINE_COLOR = '#dadada';\nconst FONT_FILL = '#555b51';\n\nfunction $(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\nexport function createSVG(tag, o) {\n\tvar element = document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tif(i === \"className\") { i = \"class\"; }\n\t\t\tif(i === \"innerHTML\") {\n\t\t\t\telement['textContent'] = val;\n\t\t\t} else {\n\t\t\t\telement.setAttribute(i, val);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n}\n\nfunction renderVerticalGradient(svgDefElem, gradientId) {\n\treturn createSVG('linearGradient', {\n\t\tinside: svgDefElem,\n\t\tid: gradientId,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: 0,\n\t\ty2: 1\n\t});\n}\n\nfunction setGradientStop(gradElem, offset, color, opacity) {\n\treturn createSVG('stop', {\n\t\t'inside': gradElem,\n\t\t'style': `stop-color: ${color}`,\n\t\t'offset': offset,\n\t\t'stop-opacity': opacity\n\t});\n}\n\nexport function makeSVGContainer(parent, className, width, height) {\n\treturn createSVG('svg', {\n\t\tclassName: className,\n\t\tinside: parent,\n\t\twidth: width,\n\t\theight: height\n\t});\n}\n\nexport function makeSVGDefs(svgContainer) {\n\treturn createSVG('defs', {\n\t\tinside: svgContainer,\n\t});\n}\n\nexport function makeSVGGroup(className, transform='', parent=undefined) {\n\tlet args = {\n\t\tclassName: className,\n\t\ttransform: transform\n\t};\n\tif(parent) args.inside = parent;\n\treturn createSVG('g', args);\n}\n\nexport function wrapInSVGGroup(elements, className='') {\n\tlet g = createSVG('g', {\n\t\tclassName: className\n\t});\n\telements.forEach(e => g.appendChild(e));\n\treturn g;\n}\n\nexport function makePath(pathStr, className='', stroke='none', fill='none', strokeWidth=2) {\n\treturn createSVG('path', {\n\t\tclassName: className,\n\t\td: pathStr,\n\t\tstyles: {\n\t\t\tstroke: stroke,\n\t\t\tfill: fill,\n\t\t\t'stroke-width': strokeWidth\n\t\t}\n\t});\n}\n\nexport function makeArcPathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];\n\treturn `M${center.x} ${center.y}\n\t\tL${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY} z`;\n}\n\nexport function makeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, center.y * 2, center.y + endPosition.y];\n\treturn `M${center.x} ${center.y}\n\t\tL${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${midArc} z\n\t\tL${arcStartX} ${midArc}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY} z`;\n}\n\nexport function makeArcStrokePathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];\n\n\treturn `M${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY}`;\n}\n\nexport function makeStrokeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, radius * 2 + arcStartY, center.y + startPosition.y];\n\n\treturn `M${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${midArc}\n\t\tM${arcStartX} ${midArc}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY}`;\n}\n\nexport function makeGradient(svgDefElem, color, lighter = false) {\n\tlet gradientId ='path-fill-gradient' + '-' + color + '-' +(lighter ? 'lighter' : 'default');\n\tlet gradientDef = renderVerticalGradient(svgDefElem, gradientId);\n\tlet opacities = [1, 0.6, 0.2];\n\tif(lighter) {\n\t\topacities = [0.4, 0.2, 0];\n\t}\n\n\tsetGradientStop(gradientDef, \"0%\", color, opacities[0]);\n\tsetGradientStop(gradientDef, \"50%\", color, opacities[1]);\n\tsetGradientStop(gradientDef, \"100%\", color, opacities[2]);\n\n\treturn gradientId;\n}\n\nexport function percentageBar(x, y, width, height,\n\tdepth=PERCENTAGE_BAR_DEFAULT_DEPTH, fill='none') {\n\n\tlet args = {\n\t\tclassName: 'percentage-bar',\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height,\n\t\tfill: fill,\n\t\tstyles: {\n\t\t\t'stroke': lightenDarkenColor(fill, -25),\n\t\t\t// Diabolically good: https://stackoverflow.com/a/9000859\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray\n\t\t\t'stroke-dasharray': `0, ${height + width}, ${width}, ${height}`,\n\t\t\t'stroke-width': depth\n\t\t},\n\t};\n\n\treturn createSVG(\"rect\", args);\n}\n\nexport function heatSquare(className, x, y, size, radius, fill='none', data={}) {\n\tlet args = {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: size,\n\t\theight: size,\n\t\trx: radius,\n\t\tfill: fill\n\t};\n\n\tObject.keys(data).map(key => {\n\t\targs[key] = data[key];\n\t});\n\n\treturn createSVG(\"rect\", args);\n}\n\nexport function legendBar(x, y, size, fill='none', label, truncate=false) {\n\tlabel = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;\n\n\tlet args = {\n\t\tclassName: 'legend-bar',\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: size,\n\t\theight: '2px',\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE * 2) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"rect\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nexport function legendDot(x, y, size, fill='none', label, truncate=false) {\n\tlabel = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;\n\n\tlet args = {\n\t\tclassName: 'legend-dot',\n\t\tcx: 0,\n\t\tcy: 0,\n\t\tr: size,\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdx: (FONT_SIZE) + 'px',\n\t\tdy: (FONT_SIZE/3) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"circle\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nexport function makeText(className, x, y, content, options = {}) {\n\tlet fontSize = options.fontSize || FONT_SIZE;\n\tlet dy = options.dy !== undefined ? options.dy : (fontSize / 2);\n\tlet fill = options.fill || FONT_FILL;\n\tlet textAnchor = options.textAnchor || 'start';\n\treturn createSVG('text', {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\tdy: dy + 'px',\n\t\t'font-size': fontSize + 'px',\n\t\tfill: fill,\n\t\t'text-anchor': textAnchor,\n\t\tinnerHTML: content\n\t});\n}\n\nfunction makeVertLine(x, label, y1, y2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tlet l = createSVG('line', {\n\t\tclassName: 'line-vertical ' + options.className,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: y1,\n\t\ty2: y2,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: 0,\n\t\ty: y1 > y2 ? y1 + LABEL_MARGIN : y1 - LABEL_MARGIN - FONT_SIZE,\n\t\tdy: FONT_SIZE + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'middle',\n\t\tinnerHTML: label + \"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(${ x }, 0)`\n\t});\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nfunction makeHoriLine(y, label, x1, x2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.lineType) options.lineType = '';\n\tif (options.shortenNumbers) label = shortenLargeNumber(label);\n\n\tlet className = 'line-horizontal ' + options.className +\n\t\t(options.lineType === \"dashed\" ? \"dashed\": \"\");\n\n\tlet l = createSVG('line', {\n\t\tclassName: className,\n\t\tx1: x1,\n\t\tx2: x2,\n\t\ty1: 0,\n\t\ty2: 0,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: x1 < x2 ? x1 - LABEL_MARGIN : x1 + LABEL_MARGIN,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / 2 - 2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': x1 < x2 ? 'end' : 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(0, ${y})`,\n\t\t'stroke-opacity': 1\n\t});\n\n\tif(text === 0 || text === '0') {\n\t\tline.style.stroke = \"rgba(27, 31, 35, 0.6)\";\n\t}\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nexport function yLine(y, label, width, options={}) {\n\tif (!isValidNumber(y)) y = 0;\n\n\tif(!options.pos) options.pos = 'left';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\tlet x1 = -1 * AXIS_TICK_LENGTH;\n\tlet x2 = options.mode === 'span' ? width + AXIS_TICK_LENGTH : 0;\n\n\tif(options.mode === 'tick' && options.pos === 'right') {\n\t\tx1 = width + AXIS_TICK_LENGTH;\n\t\tx2 = width;\n\t}\n\n\t// let offset = options.pos === 'left' ? -1 * options.offset : options.offset;\n\n\tx1 += options.offset;\n\tx2 += options.offset;\n\n\treturn makeHoriLine(y, label, x1, x2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType,\n\t\tshortenNumbers: options.shortenNumbers\n\t});\n}\n\nexport function xLine(x, label, height, options={}) {\n\tif (!isValidNumber(x)) x = 0;\n\n\tif(!options.pos) options.pos = 'bottom';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\t// Draw X axis line in span/tick mode with optional label\n\t// \ty2(span)\n\t// \t\t\t\t\t\t|\n\t// \t\t\t\t\t\t|\n\t//\t\t\t\tx line\t|\n\t//\t\t\t\t\t\t|\n\t// \t\t\t\t\t \t|\n\t// ---------------------+-- y2(tick)\n\t//\t\t\t\t\t\t|\n\t//\t\t\t\t\t\t\ty1\n\n\tlet y1 = height + AXIS_TICK_LENGTH;\n\tlet y2 = options.mode === 'span' ? -1 * AXIS_TICK_LENGTH : height;\n\n\tif(options.mode === 'tick' && options.pos === 'top') {\n\t\t// top axis ticks\n\t\ty1 = -1 * AXIS_TICK_LENGTH;\n\t\ty2 = 0;\n\t}\n\n\treturn makeVertLine(x, label, y1, y2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType\n\t});\n}\n\nexport function yMarker(y, label, width, options={}) {\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label, 5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = makeHoriLine(y, '', 0, width, {\n\t\tstroke: options.stroke || BASE_LINE_COLOR,\n\t\tclassName: options.className || '',\n\t\tlineType: options.lineType\n\t});\n\n\tline.appendChild(labelSvg);\n\n\treturn line;\n}\n\nexport function yRegion(y1, y2, width, label, options={}) {\n\t// return a group\n\tlet height = y1 - y2;\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`, // remove class\n\t\tstyles: {\n\t\t\tfill: `rgba(228, 234, 239, 0.49)`,\n\t\t\tstroke: BASE_LINE_COLOR,\n\t\t\t'stroke-dasharray': `${width}, ${height}`\n\t\t},\n\t\t// 'data-point-index': index,\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label+\"\", 4.5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet region = createSVG('g', {\n\t\ttransform: `translate(0, ${y2})`\n\t});\n\n\tregion.appendChild(rect);\n\tregion.appendChild(labelSvg);\n\n\treturn region;\n}\n\nexport function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\n\tif(height === 0) {\n\t\theight = meta.minHeight;\n\t\ty -= meta.minHeight;\n\t}\n\n\t// Preprocess numbers to avoid svg building errors\n\tif (!isValidNumber(x)) x = 0;\n\tif (!isValidNumber(y)) y = 0;\n\tif (!isValidNumber(height, true)) height = 0;\n\tif (!isValidNumber(width, true)) width = 0;\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`,\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn rect;\n\t} else {\n\t\trect.setAttribute('y', 0);\n\t\trect.setAttribute('x', 0);\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: width/2,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(rect);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nexport function datasetDot(x, y, radius, color, label='', index=0) {\n\tlet dot = createSVG('circle', {\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tcx: x,\n\t\tcy: y,\n\t\tr: radius\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn dot;\n\t} else {\n\t\tdot.setAttribute('cy', 0);\n\t\tdot.setAttribute('cx', 0);\n\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1 - radius) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(dot);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nexport function getPaths(xList, yList, color, options={}, meta={}) {\n\tlet pointsList = yList.map((y, i) => (xList[i] + ',' + y));\n\tlet pointsStr = pointsList.join(\"L\");\n\n\t// Spline\n\tif (options.spline)\n\t\tpointsStr = getSplineCurvePointsStr(xList, yList);\n\n\tlet path = makePath(\"M\"+pointsStr, 'line-graph-path', color);\n\n\t// HeatLine\n\tif(options.heatline) {\n\t\tlet gradient_id = makeGradient(meta.svgDefs, color);\n\t\tpath.style.stroke = `url(#${gradient_id})`;\n\t}\n\n\tlet paths = {\n\t\tpath: path\n\t};\n\n\t// Region\n\tif(options.regionFill) {\n\t\tlet gradient_id_region = makeGradient(meta.svgDefs, color, true);\n\n\t\tlet pathStr = \"M\" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`;\n\t\tpaths.region = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`);\n\t}\n\n\treturn paths;\n}\n\nexport let makeOverlay = {\n\t'bar': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\toverlay.style.fill = '#000000';\n\t\toverlay.style.opacity = '0.4';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'dot': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'heat_square': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t}\n};\n\nexport let updateOverlay = {\n\t'bar': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['x', 'y', 'width', 'height'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'dot': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'heat_square': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n};\n","import { getBarHeightAndYAttr, getSplineCurvePointsStr } from './draw-utils';\n\nexport const UNIT_ANIM_DUR = 350;\nexport const PATH_ANIM_DUR = 350;\nexport const MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR;\nexport const REPLACE_ALL_NEW_DUR = 250;\n\nexport const STD_EASING = 'easein';\n\nexport function translate(unit, oldCoord, newCoord, duration) {\n\tlet old = typeof oldCoord === 'string' ? oldCoord : oldCoord.join(', ');\n\treturn [\n\t\tunit,\n\t\t{transform: newCoord.join(', ')},\n\t\tduration,\n\t\tSTD_EASING,\n\t\t\"translate\",\n\t\t{transform: old}\n\t];\n}\n\nexport function translateVertLine(xLine, newX, oldX) {\n\treturn translate(xLine, [oldX, 0], [newX, 0], MARKER_LINE_ANIM_DUR);\n}\n\nexport function translateHoriLine(yLine, newY, oldY) {\n\treturn translate(yLine, [0, oldY], [0, newY], MARKER_LINE_ANIM_DUR);\n}\n\nexport function animateRegion(rectGroup, newY1, newY2, oldY2) {\n\tlet newHeight = newY1 - newY2;\n\tlet rect = rectGroup.childNodes[0];\n\tlet width = rect.getAttribute(\"width\");\n\tlet rectAnim = [\n\t\trect,\n\t\t{ height: newHeight, 'stroke-dasharray': `${width}, ${newHeight}` },\n\t\tMARKER_LINE_ANIM_DUR,\n\t\tSTD_EASING\n\t];\n\n\tlet groupAnim = translate(rectGroup, [0, oldY2], [0, newY2], MARKER_LINE_ANIM_DUR);\n\treturn [rectAnim, groupAnim];\n}\n\nexport function animateBar(bar, x, yTop, width, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\tif(bar.nodeName !== 'rect') {\n\t\tlet rect = bar.childNodes[0];\n\t\tlet rectAnim = [\n\t\t\trect,\n\t\t\t{width: width, height: height},\n\t\t\tUNIT_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\n\t\tlet oldCoordStr = bar.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(bar, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [rectAnim, groupAnim];\n\t} else {\n\t\treturn [[bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nexport function animateDot(dot, x, y) {\n\tif(dot.nodeName !== 'circle') {\n\t\tlet oldCoordStr = dot.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(dot, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [groupAnim];\n\t} else {\n\t\treturn [[dot, {cx: x, cy: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nexport function animatePath(paths, newXList, newYList, zeroLine, spline) {\n\tlet pathComponents = [];\n\tlet pointsStr = newYList.map((y, i) => (newXList[i] + ',' + y)).join(\"L\");\n\n\tif (spline)\n\t\tpointsStr = getSplineCurvePointsStr(newXList, newYList);\n\n\tconst animPath = [paths.path, {d:\"M\" + pointsStr}, PATH_ANIM_DUR, STD_EASING];\n\tpathComponents.push(animPath);\n\n\tif(paths.region) {\n\t\tlet regStartPt = `${newXList[0]},${zeroLine}L`;\n\t\tlet regEndPt = `L${newXList.slice(-1)[0]}, ${zeroLine}`;\n\n\t\tconst animRegion = [\n\t\t\tpaths.region,\n\t\t\t{d:\"M\" + regStartPt + pointsStr + regEndPt},\n\t\t\tPATH_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\t\tpathComponents.push(animRegion);\n\t}\n\n\treturn pathComponents;\n}\n\nexport function animatePathStr(oldPath, pathStr) {\n\treturn [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING];\n}\n","// Leveraging SMIL Animations\n\nimport { REPLACE_ALL_NEW_DUR } from './animate';\n\nconst EASING = {\n\tease: \"0.25 0.1 0.25 1\",\n\tlinear: \"0 0 1 1\",\n\t// easein: \"0.42 0 1 1\",\n\teasein: \"0.1 0.8 0.2 1\",\n\teaseout: \"0 0 0.58 1\",\n\teaseinout: \"0.42 0 0.58 1\"\n};\n\nfunction animateSVGElement(element, props, dur, easingType=\"linear\", type=undefined, oldValues={}) {\n\n\tlet animElement = element.cloneNode(true);\n\tlet newElement = element.cloneNode(true);\n\n\tfor(var attributeName in props) {\n\t\tlet animateElement;\n\t\tif(attributeName === 'transform') {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animateTransform\");\n\t\t} else {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animate\");\n\t\t}\n\t\tlet currentValue = oldValues[attributeName] || element.getAttribute(attributeName);\n\t\tlet value = props[attributeName];\n\n\t\tlet animAttr = {\n\t\t\tattributeName: attributeName,\n\t\t\tfrom: currentValue,\n\t\t\tto: value,\n\t\t\tbegin: \"0s\",\n\t\t\tdur: dur/1000 + \"s\",\n\t\t\tvalues: currentValue + \";\" + value,\n\t\t\tkeySplines: EASING[easingType],\n\t\t\tkeyTimes: \"0;1\",\n\t\t\tcalcMode: \"spline\",\n\t\t\tfill: 'freeze'\n\t\t};\n\n\t\tif(type) {\n\t\t\tanimAttr[\"type\"] = type;\n\t\t}\n\n\t\tfor (var i in animAttr) {\n\t\t\tanimateElement.setAttribute(i, animAttr[i]);\n\t\t}\n\n\t\tanimElement.appendChild(animateElement);\n\n\t\tif(type) {\n\t\t\tnewElement.setAttribute(attributeName, `translate(${value})`);\n\t\t} else {\n\t\t\tnewElement.setAttribute(attributeName, value);\n\t\t}\n\t}\n\n\treturn [animElement, newElement];\n}\n\nexport function transform(element, style) { // eslint-disable-line no-unused-vars\n\telement.style.transform = style;\n\telement.style.webkitTransform = style;\n\telement.style.msTransform = style;\n\telement.style.mozTransform = style;\n\telement.style.oTransform = style;\n}\n\nfunction animateSVG(svgContainer, elements) {\n\tlet newElements = [];\n\tlet animElements = [];\n\n\telements.map(element => {\n\t\tlet unit = element[0];\n\t\tlet parent = unit.parentNode;\n\n\t\tlet animElement, newElement;\n\n\t\telement[0] = unit;\n\t\t[animElement, newElement] = animateSVGElement(...element);\n\n\t\tnewElements.push(newElement);\n\t\tanimElements.push([animElement, parent]);\n\t\t\n\t\tif (parent) {\n\t\t\tparent.replaceChild(animElement, unit);\n\t\t}\n\t});\n\n\tlet animSvg = svgContainer.cloneNode(true);\n\n\tanimElements.map((animElement, i) => {\n\t\tif (animElement[1]) {\n\t\t\tanimElement[1].replaceChild(newElements[i], animElement[0]);\n\t\t\telements[i][0] = newElements[i];\n\t\t}\n\t});\n\n\treturn animSvg;\n}\n\nexport function runSMILAnimation(parent, svgElement, elementsToAnimate) {\n\tif(elementsToAnimate.length === 0) return;\n\n\tlet animSvgElement = animateSVG(svgElement, elementsToAnimate);\n\tif(svgElement.parentNode == parent) {\n\t\tparent.removeChild(svgElement);\n\t\tparent.appendChild(animSvgElement);\n\n\t}\n\n\t// Replace the new svgElement (data has already been replaced)\n\tsetTimeout(() => {\n\t\tif(animSvgElement.parentNode == parent) {\n\t\t\tparent.removeChild(animSvgElement);\n\t\t\tparent.appendChild(svgElement);\n\t\t}\n\t}, REPLACE_ALL_NEW_DUR);\n}\n","import { $ } from '../utils/dom';\nimport { CSSTEXT } from '../../css/chartsCss';\n\nexport function downloadFile(filename, data) {\n\tvar a = document.createElement('a');\n\ta.style = \"display: none\";\n\tvar blob = new Blob(data, {type: \"image/svg+xml; charset=utf-8\"});\n\tvar url = window.URL.createObjectURL(blob);\n\ta.href = url;\n\ta.download = filename;\n\tdocument.body.appendChild(a);\n\ta.click();\n\tsetTimeout(function(){\n\t\tdocument.body.removeChild(a);\n\t\twindow.URL.revokeObjectURL(url);\n\t}, 300);\n}\n\nexport function prepareForExport(svg) {\n\tlet clone = svg.cloneNode(true);\n\tclone.classList.add('chart-container');\n\tclone.setAttribute('xmlns', \"http://www.w3.org/2000/svg\");\n\tclone.setAttribute('xmlns:xlink', \"http://www.w3.org/1999/xlink\");\n\tlet styleEl = $.create('style', {\n\t\t'innerHTML': CSSTEXT\n\t});\n\tclone.insertBefore(styleEl, clone.firstChild);\n\n\tlet container = $.create('div');\n\tcontainer.appendChild(clone);\n\n\treturn container.innerHTML;\n}\n","// Playing around with dates\n\nexport const NO_OF_YEAR_MONTHS = 12;\nexport const NO_OF_DAYS_IN_WEEK = 7;\nexport const DAYS_IN_YEAR = 375;\nexport const NO_OF_MILLIS = 1000;\nexport const SEC_IN_DAY = 86400;\n\nexport const MONTH_NAMES = [\"January\", \"February\", \"March\", \"April\", \"May\",\n\t\"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"];\nexport const MONTH_NAMES_SHORT = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n\t\"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n\nexport const DAY_NAMES_SHORT = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\nexport const DAY_NAMES = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\",\n\t\"Thursday\", \"Friday\", \"Saturday\"];\n\n// https://stackoverflow.com/a/11252167/6495043\nfunction treatAsUtc(date) {\n\tlet result = new Date(date);\n\tresult.setMinutes(result.getMinutes() - result.getTimezoneOffset());\n\treturn result;\n}\n\nexport function getYyyyMmDd(date) {\n\tlet dd = date.getDate();\n\tlet mm = date.getMonth() + 1; // getMonth() is zero-based\n\treturn [\n\t\tdate.getFullYear(),\n\t\t(mm>9 ? '' : '0') + mm,\n\t\t(dd>9 ? '' : '0') + dd\n\t].join('-');\n}\n\nexport function clone(date) {\n\treturn new Date(date.getTime());\n}\n\nexport function timestampSec(date) {\n\treturn date.getTime()/NO_OF_MILLIS;\n}\n\nexport function timestampToMidnight(timestamp, roundAhead = false) {\n\tlet midnightTs = Math.floor(timestamp - (timestamp % SEC_IN_DAY));\n\tif(roundAhead) {\n\t\treturn midnightTs + SEC_IN_DAY;\n\t}\n\treturn midnightTs;\n}\n\n// export function getMonthsBetween(startDate, endDate) {}\n\nexport function getWeeksBetween(startDate, endDate) {\n\tlet weekStartDate = setDayToSunday(startDate);\n\treturn Math.ceil(getDaysBetween(weekStartDate, endDate) / NO_OF_DAYS_IN_WEEK);\n}\n\nexport function getDaysBetween(startDate, endDate) {\n\tlet millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS;\n\treturn (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay;\n}\n\nexport function areInSameMonth(startDate, endDate) {\n\treturn startDate.getMonth() === endDate.getMonth()\n\t\t&& startDate.getFullYear() === endDate.getFullYear();\n}\n\nexport function getMonthName(i, short=false) {\n\tlet monthName = MONTH_NAMES[i];\n\treturn short ? monthName.slice(0, 3) : monthName;\n}\n\nexport function getLastDateInMonth (month, year) {\n\treturn new Date(year, month + 1, 0); // 0: last day in previous month\n}\n\n// mutates\nexport function setDayToSunday(date) {\n\tlet newDate = clone(date);\n\tconst day = newDate.getDay();\n\tif(day !== 0) {\n\t\taddDays(newDate, (-1) * day);\n\t}\n\treturn newDate;\n}\n\n// mutates\nexport function addDays(date, numberOfDays) {\n\tdate.setDate(date.getDate() + numberOfDays);\n}\n","import { makeSVGGroup } from '../utils/draw';\nimport { makeText, makePath, xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, percentageBar, getPaths, heatSquare } from '../utils/draw';\nimport { equilizeNoOfElements } from '../utils/draw-utils';\nimport { translateHoriLine, translateVertLine, animateRegion, animateBar,\n\tanimateDot, animatePath, animatePathStr } from '../utils/animate';\nimport { getMonthName } from '../utils/date-utils';\n\nclass ChartComponent {\n\tconstructor({\n\t\tlayerClass = '',\n\t\tlayerTransform = '',\n\t\tconstants,\n\n\t\tgetData,\n\t\tmakeElements,\n\t\tanimateElements\n\t}) {\n\t\tthis.layerTransform = layerTransform;\n\t\tthis.constants = constants;\n\n\t\tthis.makeElements = makeElements;\n\t\tthis.getData = getData;\n\n\t\tthis.animateElements = animateElements;\n\n\t\tthis.store = [];\n\t\tthis.labels = [];\n\n\t\tthis.layerClass = layerClass;\n\t\tthis.layerClass = typeof(this.layerClass) === 'function'\n\t\t\t? this.layerClass() : this.layerClass;\n\n\t\tthis.refresh();\n\t}\n\n\trefresh(data) {\n\t\tthis.data = data || this.getData();\n\t}\n\n\tsetup(parent) {\n\t\tthis.layer = makeSVGGroup(this.layerClass, this.layerTransform, parent);\n\t}\n\n\tmake() {\n\t\tthis.render(this.data);\n\t\tthis.oldData = this.data;\n\t}\n\n\trender(data) {\n\t\tthis.store = this.makeElements(data);\n\n\t\tthis.layer.textContent = '';\n\t\tthis.store.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t\tthis.labels.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t}\n\n\tupdate(animate = true) {\n\t\tthis.refresh();\n\t\tlet animateElements = [];\n\t\tif(animate) {\n\t\t\tanimateElements = this.animateElements(this.data) || [];\n\t\t}\n\t\treturn animateElements;\n\t}\n}\n\nlet componentConfigs = {\n\tdonutSlices: {\n\t\tlayerClass: 'donut-slices',\n\t\tmakeElements(data) {\n\t\t\treturn data.sliceStrings.map((s, i) => {\n\t\t\t\tlet slice = makePath(s, 'donut-path', data.colors[i], 'none', data.strokeWidth);\n\t\t\t\tslice.style.transition = 'transform .3s;';\n\t\t\t\treturn slice;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\treturn this.store.map((slice, i) => animatePathStr(slice, newData.sliceStrings[i]));\n\t\t},\n\t},\n\tpieSlices: {\n\t\tlayerClass: 'pie-slices',\n\t\tmakeElements(data) {\n\t\t\treturn data.sliceStrings.map((s, i) =>{\n\t\t\t\tlet slice = makePath(s, 'pie-path', 'none', data.colors[i]);\n\t\t\t\tslice.style.transition = 'transform .3s;';\n\t\t\t\treturn slice;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\treturn this.store.map((slice, i) =>\n\t\t\t\tanimatePathStr(slice, newData.sliceStrings[i])\n\t\t\t);\n\t\t}\n\t},\n\tpercentageBars: {\n\t\tlayerClass: 'percentage-bars',\n\t\tmakeElements(data) {\n\t\t\treturn data.xPositions.map((x, i) =>{\n\t\t\t\tlet y = 0;\n\t\t\t\tlet bar = percentageBar(x, y, data.widths[i],\n\t\t\t\t\tthis.constants.barHeight, this.constants.barDepth, data.colors[i]);\n\t\t\t\treturn bar;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\tyAxis: {\n\t\tlayerClass: 'y axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\tyLine(position, data.labels[i], this.constants.width,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos, shortenNumbers: this.constants.shortenNumbers})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.labels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tlabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\txAxis: {\n\t\tlayerClass: 'x axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\txLine(position, data.calcLabels[i], this.constants.height,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.calcLabels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.calcLabels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tcalcLabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateVertLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyMarkers: {\n\t\tlayerClass: 'y-markers',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(m =>\n\t\t\t\tyMarker(m.position, m.label, this.constants.width,\n\t\t\t\t\t{labelPos: m.options.labelPos, mode: 'span', lineType: 'dashed'})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.position);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.position);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tposition: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyRegions: {\n\t\tlayerClass: 'y-regions',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(r =>\n\t\t\t\tyRegion(r.startPos, r.endPos, this.constants.width,\n\t\t\t\t\tr.label, {labelPos: r.options.labelPos})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.endPos);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newStarts = newData.map(d => d.startPos);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.endPos);\n\t\t\tlet oldStarts = this.oldData.map(d => d.startPos);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tstartPos: oldStarts[i],\n\t\t\t\t\tendPos: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((rectGroup, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateRegion(\n\t\t\t\t\trectGroup, newStarts[i], newPos[i], oldPos[i]\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\theatDomain: {\n\t\tlayerClass: function() { return 'heat-domain domain-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet {index, colWidth, rowHeight, squareSize, radius, xTranslate} = this.constants;\n\t\t\tlet monthNameHeight = -12;\n\t\t\tlet x = xTranslate, y = 0;\n\n\t\t\tthis.serializedSubDomains = [];\n\n\t\t\tdata.cols.map((week, weekNo) => {\n\t\t\t\tif(weekNo === 1) {\n\t\t\t\t\tthis.labels.push(\n\t\t\t\t\t\tmakeText('domain-name', x, monthNameHeight, getMonthName(index, true).toUpperCase(),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfontSize: 9\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tweek.map((day, i) => {\n\t\t\t\t\tif(day.fill) {\n\t\t\t\t\t\tlet data = {\n\t\t\t\t\t\t\t'data-date': day.yyyyMmDd,\n\t\t\t\t\t\t\t'data-value': day.dataValue,\n\t\t\t\t\t\t\t'data-day': i\n\t\t\t\t\t\t};\n\t\t\t\t\t\tlet square = heatSquare('day', x, y, squareSize, radius, day.fill, data);\n\t\t\t\t\t\tthis.serializedSubDomains.push(square);\n\t\t\t\t\t}\n\t\t\t\t\ty += rowHeight;\n\t\t\t\t});\n\t\t\t\ty = 0;\n\t\t\t\tx += colWidth;\n\t\t\t});\n\n\t\t\treturn this.serializedSubDomains;\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\n\tbarGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'bar';\n\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\treturn datasetBar(\n\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\ty,\n\t\t\t\t\tdata.barWidth,\n\t\t\t\t\tc.color,\n\t\t\t\t\tdata.labels[j],\n\t\t\t\t\tj,\n\t\t\t\t\tdata.offsets[j],\n\t\t\t\t\t{\n\t\t\t\t\t\tzeroLine: data.zeroLine,\n\t\t\t\t\t\tbarsWidth: data.barsWidth,\n\t\t\t\t\t\tminHeight: c.minHeight\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn this.units;\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newOffsets = newData.offsets;\n\t\t\tlet newLabels = newData.labels;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldOffsets = this.oldData.offsets;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldOffsets, newOffsets] = equilizeNoOfElements(oldOffsets, newOffsets);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\toffsets: oldOffsets,\n\t\t\t\tlabels: newLabels,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tbarsWidth: this.oldData.barsWidth,\n\t\t\t\tbarWidth: this.oldData.barWidth,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((bar, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateBar(\n\t\t\t\t\tbar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i],\n\t\t\t\t\t{zeroLine: newData.zeroLine}\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\tlineGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'dot';\n\t\t\tthis.paths = {};\n\t\t\tif(!c.hideLine) {\n\t\t\t\tthis.paths = getPaths(\n\t\t\t\t\tdata.xPositions,\n\t\t\t\t\tdata.yPositions,\n\t\t\t\t\tc.color,\n\t\t\t\t\t{\n\t\t\t\t\t\theatline: c.heatline,\n\t\t\t\t\t\tregionFill: c.regionFill,\n\t\t\t\t\t\tspline: c.spline\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsvgDefs: c.svgDefs,\n\t\t\t\t\t\tzeroLine: data.zeroLine\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.units = [];\n\t\t\tif(!c.hideDots) {\n\t\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\t\treturn datasetDot(\n\t\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\t\ty,\n\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\tc.color,\n\t\t\t\t\t\t(c.valuesOverPoints ? data.values[j] : ''),\n\t\t\t\t\t\tj\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn Object.values(this.paths).concat(this.units);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newValues = newData.values;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldValues = this.oldData.values;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldValues, newValues] = equilizeNoOfElements(oldValues, newValues);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\tvalues: newValues,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tradius: this.oldData.radius,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tif(Object.keys(this.paths).length) {\n\t\t\t\tanimateElements = animateElements.concat(animatePath(\n\t\t\t\t\tthis.paths, newXPos, newYPos, newData.zeroLine, this.constants.spline));\n\t\t\t}\n\n\t\t\tif(this.units.length) {\n\t\t\t\tthis.units.map((dot, i) => {\n\t\t\t\t\tanimateElements = animateElements.concat(animateDot(\n\t\t\t\t\t\tdot, newXPos[i], newYPos[i]));\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn animateElements;\n\t\t}\n\t}\n};\n\nexport function getComponent(name, constants, getData) {\n\tlet keys = Object.keys(componentConfigs).filter(k => name.includes(k));\n\tlet config = componentConfigs[keys[0]];\n\tObject.assign(config, {\n\t\tconstants: constants,\n\t\tgetData: getData\n\t});\n\treturn new ChartComponent(config);\n}\n","import { floatTwo } from './helpers';\n\nfunction normalize(x) {\n\t// Calculates mantissa and exponent of a number\n\t// Returns normalized number and exponent\n\t// https://stackoverflow.com/q/9383593/6495043\n\n\tif(x===0) {\n\t\treturn [0, 0];\n\t}\n\tif(isNaN(x)) {\n\t\treturn {mantissa: -6755399441055744, exponent: 972};\n\t}\n\tvar sig = x > 0 ? 1 : -1;\n\tif(!isFinite(x)) {\n\t\treturn {mantissa: sig * 4503599627370496, exponent: 972};\n\t}\n\n\tx = Math.abs(x);\n\tvar exp = Math.floor(Math.log10(x));\n\tvar man = x/Math.pow(10, exp);\n\n\treturn [sig * man, exp];\n}\n\nfunction getChartRangeIntervals(max, min=0) {\n\tlet upperBound = Math.ceil(max);\n\tlet lowerBound = Math.floor(min);\n\tlet range = upperBound - lowerBound;\n\n\tlet noOfParts = range;\n\tlet partSize = 1;\n\n\t// To avoid too many partitions\n\tif(range > 5) {\n\t\tif(range % 2 !== 0) {\n\t\t\tupperBound++;\n\t\t\t// Recalc range\n\t\t\trange = upperBound - lowerBound;\n\t\t}\n\t\tnoOfParts = range/2;\n\t\tpartSize = 2;\n\t}\n\n\t// Special case: 1 and 2\n\tif(range <= 2) {\n\t\tnoOfParts = 4;\n\t\tpartSize = range/noOfParts;\n\t}\n\n\t// Special case: 0\n\tif(range === 0) {\n\t\tnoOfParts = 5;\n\t\tpartSize = 1;\n\t}\n\n\tlet intervals = [];\n\tfor(var i = 0; i <= noOfParts; i++){\n\t\tintervals.push(lowerBound + partSize * i);\n\t}\n\treturn intervals;\n}\n\nfunction getChartIntervals(maxValue, minValue=0) {\n\tlet [normalMaxValue, exponent] = normalize(maxValue);\n\tlet normalMinValue = minValue ? minValue/Math.pow(10, exponent): 0;\n\n\t// Allow only 7 significant digits\n\tnormalMaxValue = normalMaxValue.toFixed(6);\n\n\tlet intervals = getChartRangeIntervals(normalMaxValue, normalMinValue);\n\tintervals = intervals.map(value => value * Math.pow(10, exponent));\n\treturn intervals;\n}\n\nexport function calcChartIntervals(values, withMinimum=false) {\n\t//*** Where the magic happens ***\n\n\t// Calculates best-fit y intervals from given values\n\t// and returns the interval array\n\n\tlet maxValue = Math.max(...values);\n\tlet minValue = Math.min(...values);\n\n\t// Exponent to be used for pretty print\n\tlet exponent = 0, intervals = []; // eslint-disable-line no-unused-vars\n\n\tfunction getPositiveFirstIntervals(maxValue, absMinValue) {\n\t\tlet intervals = getChartIntervals(maxValue);\n\n\t\tlet intervalSize = intervals[1] - intervals[0];\n\n\t\t// Then unshift the negative values\n\t\tlet value = 0;\n\t\tfor(var i = 1; value < absMinValue; i++) {\n\t\t\tvalue += intervalSize;\n\t\t\tintervals.unshift((-1) * value);\n\t\t}\n\t\treturn intervals;\n\t}\n\n\t// CASE I: Both non-negative\n\n\tif(maxValue >= 0 && minValue >= 0) {\n\t\texponent = normalize(maxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(maxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(maxValue, minValue);\n\t\t}\n\t}\n\n\t// CASE II: Only minValue negative\n\n\telse if(maxValue > 0 && minValue < 0) {\n\t\t// `withMinimum` irrelevant in this case,\n\t\t// We'll be handling both sides of zero separately\n\t\t// (both starting from zero)\n\t\t// Because ceil() and floor() behave differently\n\t\t// in those two regions\n\n\t\tlet absMinValue = Math.abs(minValue);\n\n\t\tif(maxValue >= absMinValue) {\n\t\t\texponent = normalize(maxValue)[1];\n\t\t\tintervals = getPositiveFirstIntervals(maxValue, absMinValue);\n\t\t} else {\n\t\t\t// Mirror: maxValue => absMinValue, then change sign\n\t\t\texponent = normalize(absMinValue)[1];\n\t\t\tlet posIntervals = getPositiveFirstIntervals(absMinValue, maxValue);\n\t\t\tintervals = posIntervals.reverse().map(d => d * (-1));\n\t\t}\n\n\t}\n\n\t// CASE III: Both non-positive\n\n\telse if(maxValue <= 0 && minValue <= 0) {\n\t\t// Mirrored Case I:\n\t\t// Work with positives, then reverse the sign and array\n\n\t\tlet pseudoMaxValue = Math.abs(minValue);\n\t\tlet pseudoMinValue = Math.abs(maxValue);\n\n\t\texponent = normalize(pseudoMaxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue, pseudoMinValue);\n\t\t}\n\n\t\tintervals = intervals.reverse().map(d => d * (-1));\n\t}\n\n\treturn intervals;\n}\n\nexport function getZeroIndex(yPts) {\n\tlet zeroIndex;\n\tlet interval = getIntervalSize(yPts);\n\tif(yPts.indexOf(0) >= 0) {\n\t\t// the range has a given zero\n\t\t// zero-line on the chart\n\t\tzeroIndex = yPts.indexOf(0);\n\t} else if(yPts[0] > 0) {\n\t\t// Minimum value is positive\n\t\t// zero-line is off the chart: below\n\t\tlet min = yPts[0];\n\t\tzeroIndex = (-1) * min / interval;\n\t} else {\n\t\t// Maximum value is negative\n\t\t// zero-line is off the chart: above\n\t\tlet max = yPts[yPts.length - 1];\n\t\tzeroIndex = (-1) * max / interval + (yPts.length - 1);\n\t}\n\treturn zeroIndex;\n}\n\nexport function getRealIntervals(max, noOfIntervals, min = 0, asc = 1) {\n\tlet range = max - min;\n\tlet part = range * 1.0 / noOfIntervals;\n\tlet intervals = [];\n\n\tfor(var i = 0; i <= noOfIntervals; i++) {\n\t\tintervals.push(min + part * i);\n\t}\n\n\treturn asc ? intervals : intervals.reverse();\n}\n\nexport function getIntervalSize(orderedArray) {\n\treturn orderedArray[1] - orderedArray[0];\n}\n\nexport function getValueRange(orderedArray) {\n\treturn orderedArray[orderedArray.length-1] - orderedArray[0];\n}\n\nexport function scale(val, yAxis) {\n\treturn floatTwo(yAxis.zeroLine - val * yAxis.scaleMultiplier);\n}\n\nexport function isInRange(val, min, max) {\n\treturn val > min && val < max;\n}\n\nexport function isInRange2D(coord, minCoord, maxCoord) {\n\treturn isInRange(coord[0], minCoord[0], maxCoord[0])\n\t\t&& isInRange(coord[1], minCoord[1], maxCoord[1]);\n}\n\nexport function getClosestInArray(goal, arr, index = false) {\n\tlet closest = arr.reduce(function(prev, curr) {\n\t\treturn (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);\n\t}, []);\n\n\treturn index ? arr.indexOf(closest) : closest;\n}\n\nexport function calcDistribution(values, distributionSize) {\n\t// Assume non-negative values,\n\t// implying distribution minimum at zero\n\n\tlet dataMaxValue = Math.max(...values);\n\n\tlet distributionStep = 1 / (distributionSize - 1);\n\tlet distribution = [];\n\n\tfor(var i = 0; i < distributionSize; i++) {\n\t\tlet checkpoint = dataMaxValue * (distributionStep * i);\n\t\tdistribution.push(checkpoint);\n\t}\n\n\treturn distribution;\n}\n\nexport function getMaxCheckpoint(value, distribution) {\n\treturn distribution.filter(d => d < value).length;\n}\n","import { fillArray } from '../utils/helpers';\nimport { DEFAULT_AXIS_CHART_TYPE, AXIS_DATASET_CHART_TYPES, DEFAULT_CHAR_WIDTH } from '../utils/constants';\n\nexport function dataPrep(data, type) {\n\tdata.labels = data.labels || [];\n\n\tlet datasetLength = data.labels.length;\n\n\t// Datasets\n\tlet datasets = data.datasets;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\tif(!datasets) {\n\t\t// default\n\t\tdatasets = [{\n\t\t\tvalues: zeroArray\n\t\t}];\n\t}\n\n\tdatasets.map(d=> {\n\t\t// Set values\n\t\tif(!d.values) {\n\t\t\td.values = zeroArray;\n\t\t} else {\n\t\t\t// Check for non values\n\t\t\tlet vals = d.values;\n\t\t\tvals = vals.map(val => (!isNaN(val) ? val : 0));\n\n\t\t\t// Trim or extend\n\t\t\tif(vals.length > datasetLength) {\n\t\t\t\tvals = vals.slice(0, datasetLength);\n\t\t\t} else {\n\t\t\t\tvals = fillArray(vals, datasetLength - vals.length, 0);\n\t\t\t}\n\t\t\td.values = vals;\n\t\t}\n\n\t\t// Set type\n\t\tif(!d.chartType ) {\n\t\t\tif(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;\n\t\t\td.chartType = type;\n\t\t}\n\n\t});\n\n\t// Markers\n\n\t// Regions\n\t// data.yRegions = data.yRegions || [];\n\tif(data.yRegions) {\n\t\tdata.yRegions.map(d => {\n\t\t\tif(d.end < d.start) {\n\t\t\t\t[d.start, d.end] = [d.end, d.start];\n\t\t\t}\n\t\t});\n\t}\n\n\treturn data;\n}\n\nexport function zeroDataPrep(realData) {\n\tlet datasetLength = realData.labels.length;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\n\tlet zeroData = {\n\t\tlabels: realData.labels.slice(0, -1),\n\t\tdatasets: realData.datasets.map(d => {\n\t\t\treturn {\n\t\t\t\tname: '',\n\t\t\t\tvalues: zeroArray.slice(0, -1),\n\t\t\t\tchartType: d.chartType\n\t\t\t};\n\t\t}),\n\t};\n\n\tif(realData.yMarkers) {\n\t\tzeroData.yMarkers = [\n\t\t\t{\n\t\t\t\tvalue: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\tif(realData.yRegions) {\n\t\tzeroData.yRegions = [\n\t\t\t{\n\t\t\t\tstart: 0,\n\t\t\t\tend: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\treturn zeroData;\n}\n\nexport function getShortenedLabels(chartWidth, labels=[], isSeries=true) {\n\tlet allowedSpace = chartWidth / labels.length;\n\tif(allowedSpace <= 0) allowedSpace = 1;\n\tlet allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;\n\n\tlet seriesMultiple;\n\tif(isSeries) {\n\t\t// Find the maximum label length for spacing calculations\n\t\tlet maxLabelLength = Math.max(...labels.map(label => label.length));\n\t\tseriesMultiple = Math.ceil(maxLabelLength/allowedLetters);\n\t}\n\n\tlet calcLabels = labels.map((label, i) => {\n\t\tlabel += \"\";\n\t\tif(label.length > allowedLetters) {\n\n\t\t\tif(!isSeries) {\n\t\t\t\tif(allowedLetters-3 > 0) {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters-3) + \" ...\";\n\t\t\t\t} else {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters) + '..';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(i % seriesMultiple !== 0) {\n\t\t\t\t\tlabel = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn label;\n\t});\n\n\treturn calcLabels;\n}\n","import '../css/charts.scss';\n\n// import MultiAxisChart from './charts/MultiAxisChart';\nimport PercentageChart from './charts/PercentageChart';\nimport PieChart from './charts/PieChart';\nimport Heatmap from './charts/Heatmap';\nimport AxisChart from './charts/AxisChart';\nimport DonutChart from './charts/DonutChart';\n\nconst chartTypes = {\n\tbar: AxisChart,\n\tline: AxisChart,\n\t// multiaxis: MultiAxisChart,\n\tpercentage: PercentageChart,\n\theatmap: Heatmap,\n\tpie: PieChart,\n\tdonut: DonutChart,\n};\n\nfunction getChartByType(chartType = 'line', parent, options) {\n\tif (chartType === 'axis-mixed') {\n\t\toptions.type = 'line';\n\t\treturn new AxisChart(parent, options);\n\t}\n\n\tif (!chartTypes[chartType]) {\n\t\tconsole.error(\"Undefined chart type: \" + chartType);\n\t\treturn;\n\t}\n\n\treturn new chartTypes[chartType](parent, options);\n}\n\nclass Chart {\n\tconstructor(parent, options) {\n\t\treturn getChartByType(options.type, parent, options);\n\t}\n}\n\nexport { Chart, PercentageChart, PieChart, Heatmap, AxisChart };","import { $ } from '../utils/dom';\nimport { TOOLTIP_POINTER_TRIANGLE_HEIGHT } from '../utils/constants';\n\nexport default class SvgTip {\n\tconstructor({\n\t\tparent = null,\n\t\tcolors = []\n\t}) {\n\t\tthis.parent = parent;\n\t\tthis.colors = colors;\n\t\tthis.titleName = '';\n\t\tthis.titleValue = '';\n\t\tthis.listValues = [];\n\t\tthis.titleValueFirst = 0;\n\n\t\tthis.x = 0;\n\t\tthis.y = 0;\n\n\t\tthis.top = 0;\n\t\tthis.left = 0;\n\n\t\tthis.setup();\n\t}\n\n\tsetup() {\n\t\tthis.makeTooltip();\n\t}\n\n\trefresh() {\n\t\tthis.fill();\n\t\tthis.calcPosition();\n\t}\n\n\tmakeTooltip() {\n\t\tthis.container = $.create('div', {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'graph-svg-tip comparison',\n\t\t\tinnerHTML: `\n\t\t\t\t
        \n\t\t\t\t
        `\n\t\t});\n\t\tthis.hideTip();\n\n\t\tthis.title = this.container.querySelector('.title');\n\t\tthis.dataPointList = this.container.querySelector('.data-point-list');\n\n\t\tthis.parent.addEventListener('mouseleave', () => {\n\t\t\tthis.hideTip();\n\t\t});\n\t}\n\n\tfill() {\n\t\tlet title;\n\t\tif(this.index) {\n\t\t\tthis.container.setAttribute('data-point-index', this.index);\n\t\t}\n\t\tif(this.titleValueFirst) {\n\t\t\ttitle = `${this.titleValue}${this.titleName}`;\n\t\t} else {\n\t\t\ttitle = `${this.titleName}${this.titleValue}`;\n\t\t}\n\t\tthis.title.innerHTML = title;\n\t\tthis.dataPointList.innerHTML = '';\n\n\t\tthis.listValues.map((set, i) => {\n\t\t\tconst color = this.colors[i] || 'black';\n\t\t\tlet value = set.formatted === 0 || set.formatted ? set.formatted : set.value;\n\n\t\t\tlet li = $.create('li', {\n\t\t\t\tstyles: {\n\t\t\t\t\t'border-top': `3px solid ${color}`\n\t\t\t\t},\n\t\t\t\tinnerHTML: `${ value === 0 || value ? value : '' }\n\t\t\t\t\t${set.title ? set.title : '' }`\n\t\t\t});\n\n\t\t\tthis.dataPointList.appendChild(li);\n\t\t});\n\t}\n\n\tcalcPosition() {\n\t\tlet width = this.container.offsetWidth;\n\n\t\tthis.top = this.y - this.container.offsetHeight\n\t\t\t- TOOLTIP_POINTER_TRIANGLE_HEIGHT;\n\t\tthis.left = this.x - width/2;\n\t\tlet maxLeft = this.parent.offsetWidth - width;\n\n\t\tlet pointer = this.container.querySelector('.svg-pointer');\n\n\t\tif(this.left < 0) {\n\t\t\tpointer.style.left = `calc(50% - ${-1 * this.left}px)`;\n\t\t\tthis.left = 0;\n\t\t} else if(this.left > maxLeft) {\n\t\t\tlet delta = this.left - maxLeft;\n\t\t\tlet pointerOffset = `calc(50% + ${delta}px)`;\n\t\t\tpointer.style.left = pointerOffset;\n\n\t\t\tthis.left = maxLeft;\n\t\t} else {\n\t\t\tpointer.style.left = `50%`;\n\t\t}\n\t}\n\n\tsetValues(x, y, title = {}, listValues = [], index = -1) {\n\t\tthis.titleName = title.name;\n\t\tthis.titleValue = title.value;\n\t\tthis.listValues = listValues;\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.titleValueFirst = title.valueFirst || 0;\n\t\tthis.index = index;\n\t\tthis.refresh();\n\t}\n\n\thideTip() {\n\t\tthis.container.style.top = '0px';\n\t\tthis.container.style.left = '0px';\n\t\tthis.container.style.opacity = '0';\n\t}\n\n\tshowTip() {\n\t\tthis.container.style.top = this.top + 'px';\n\t\tthis.container.style.left = this.left + 'px';\n\t\tthis.container.style.opacity = '1';\n\t}\n}\n","export const CSSTEXT = \".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}\";","import SvgTip from '../objects/SvgTip';\nimport { $, isElementInViewport, getElementContentWidth, isHidden } from '../utils/dom';\nimport { makeSVGContainer, makeSVGDefs, makeSVGGroup, makeText } from '../utils/draw';\nimport { BASE_MEASURES, getExtraHeight, getExtraWidth, getTopOffset, getLeftOffset,\n\tINIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS} from '../utils/constants';\nimport { getColor, isValidColor } from '../utils/colors';\nimport { runSMILAnimation } from '../utils/animation';\nimport { downloadFile, prepareForExport } from '../utils/export';\nimport { deepClone } from '../utils/helpers';\n\nexport default class BaseChart {\n\tconstructor(parent, options) {\n\t\t// deepclone options to avoid making changes to orignal object\n\t\toptions = deepClone(options);\n\n\t\tthis.parent = typeof parent === 'string'\n\t\t\t? document.querySelector(parent)\n\t\t\t: parent;\n\n\t\tif (!(this.parent instanceof HTMLElement)) {\n\t\t\tthrow new Error('No `parent` element to render on was provided.');\n\t\t}\n\n\t\tthis.rawChartArgs = options;\n\n\t\tthis.title = options.title || '';\n\t\tthis.type = options.type || '';\n\n\t\tthis.realData = this.prepareData(options.data);\n\t\tthis.data = this.prepareFirstData(this.realData);\n\n\t\tthis.colors = this.validateColors(options.colors, this.type);\n\n\t\tthis.config = {\n\t\t\tshowTooltip: 1, // calculate\n\t\t\tshowLegend: 1, // calculate\n\t\t\tisNavigable: options.isNavigable || 0,\n\t\t\tanimate: (typeof options.animate !== 'undefined') ? options.animate : 1,\n\t\t\ttruncateLegends: options.truncateLegends || 1\n\t\t};\n\n\t\tthis.measures = JSON.parse(JSON.stringify(BASE_MEASURES));\n\t\tlet m = this.measures;\n\t\tthis.setMeasures(options);\n\t\tif(!this.title.length) { m.titleHeight = 0; }\n\t\tif(!this.config.showLegend) m.legendHeight = 0;\n\t\tthis.argHeight = options.height || m.baseHeight;\n\n\t\tthis.state = {};\n\t\tthis.options = {};\n\n\t\tthis.initTimeout = INIT_CHART_UPDATE_TIMEOUT;\n\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.overlays = [];\n\t\t}\n\n\t\tthis.configure(options);\n\t}\n\n\tprepareData(data) {\n\t\treturn data;\n\t}\n\n\tprepareFirstData(data) {\n\t\treturn data;\n\t}\n\n\tvalidateColors(colors, type) {\n\t\tconst validColors = [];\n\t\tcolors = (colors || []).concat(DEFAULT_COLORS[type]);\n\t\tcolors.forEach((string) => {\n\t\t\tconst color = getColor(string);\n\t\t\tif(!isValidColor(color)) {\n\t\t\t\tconsole.warn('\"' + string + '\" is not a valid color.');\n\t\t\t} else {\n\t\t\t\tvalidColors.push(color);\n\t\t\t}\n\t\t});\n\t\treturn validColors;\n\t}\n\n\tsetMeasures() {\n\t\t// Override measures, including those for title and legend\n\t\t// set config for legend and title\n\t}\n\n\tconfigure() {\n\t\tlet height = this.argHeight;\n\t\tthis.baseHeight = height;\n\t\tthis.height = height - getExtraHeight(this.measures);\n\n\t\t// Bind window events\n\t\tthis.boundDrawFn = () => this.draw(true);\n\t\tif (ResizeObserver) {\n\t\t\tthis.resizeObserver = new ResizeObserver(this.boundDrawFn);\n\t\t\tthis.resizeObserver.observe(this.parent);\n\t\t}\n\t\twindow.addEventListener('resize', this.boundDrawFn);\n\t\twindow.addEventListener('orientationchange', this.boundDrawFn);\n\t}\n\n\tdestroy() {\n\t\tif (this.resizeObserver) this.resizeObserver.disconnect();\n\t\twindow.removeEventListener('resize', this.boundDrawFn);\n\t\twindow.removeEventListener('orientationchange', this.boundDrawFn);\n\t}\n\n\t// Has to be called manually\n\tsetup() {\n\t\tthis.makeContainer();\n\t\tthis.updateWidth();\n\t\tthis.makeTooltip();\n\n\t\tthis.draw(false, true);\n\t}\n\n\tmakeContainer() {\n\t\t// Chart needs a dedicated parent element\n\t\tthis.parent.innerHTML = '';\n\n\t\tlet args = {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'chart-container'\n\t\t};\n\n\t\tif(this.independentWidth) {\n\t\t\targs.styles = { width: this.independentWidth + 'px' };\n\t\t}\n\n\t\tthis.container = $.create('div', args);\n\t}\n\n\tmakeTooltip() {\n\t\tthis.tip = new SvgTip({\n\t\t\tparent: this.container,\n\t\t\tcolors: this.colors\n\t\t});\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {}\n\n\tdraw(onlyWidthChange=false, init=false) {\n\t\tif (onlyWidthChange && isHidden(this.parent)) {\n\t\t\t// Don't update anything if the chart is hidden\n\t\t\treturn;\n\t\t}\n\t\tthis.updateWidth();\n\n\t\tthis.calc(onlyWidthChange);\n\t\tthis.makeChartArea();\n\t\tthis.setupComponents();\n\n\t\tthis.components.forEach(c => c.setup(this.drawArea));\n\t\t// this.components.forEach(c => c.make());\n\t\tthis.render(this.components, false);\n\n\t\tif(init) {\n\t\t\tthis.data = this.realData;\n\t\t\tsetTimeout(() => {this.update(this.data);}, this.initTimeout);\n\t\t}\n\n\t\tthis.renderLegend();\n\n\t\tthis.setupNavigation(init);\n\t}\n\n\tcalc() {} // builds state\n\n\tupdateWidth() {\n\t\tthis.baseWidth = getElementContentWidth(this.parent);\n\t\tthis.width = this.baseWidth - getExtraWidth(this.measures);\n\t}\n\n\tmakeChartArea() {\n\t\tif(this.svg) {\n\t\t\tthis.container.removeChild(this.svg);\n\t\t}\n\t\tlet m = this.measures;\n\n\t\tthis.svg = makeSVGContainer(\n\t\t\tthis.container,\n\t\t\t'frappe-chart chart',\n\t\t\tthis.baseWidth,\n\t\t\tthis.baseHeight\n\t\t);\n\t\tthis.svgDefs = makeSVGDefs(this.svg);\n\n\t\tif(this.title.length) {\n\t\t\tthis.titleEL = makeText(\n\t\t\t\t'title',\n\t\t\t\tm.margins.left,\n\t\t\t\tm.margins.top,\n\t\t\t\tthis.title,\n\t\t\t\t{\n\t\t\t\t\tfontSize: m.titleFontSize,\n\t\t\t\t\tfill: '#666666',\n\t\t\t\t\tdy: m.titleFontSize\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tlet top = getTopOffset(m);\n\t\tthis.drawArea = makeSVGGroup(\n\t\t\tthis.type + '-chart chart-draw-area',\n\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t);\n\n\t\tif(this.config.showLegend) {\n\t\t\ttop += this.height + m.paddings.bottom;\n\t\t\tthis.legendArea = makeSVGGroup(\n\t\t\t\t'chart-legend',\n\t\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t\t);\n\t\t}\n\n\t\tif(this.title.length) { this.svg.appendChild(this.titleEL); }\n\t\tthis.svg.appendChild(this.drawArea);\n\t\tif(this.config.showLegend) { this.svg.appendChild(this.legendArea); }\n\n\t\tthis.updateTipOffset(getLeftOffset(m), getTopOffset(m));\n\t}\n\n\tupdateTipOffset(x, y) {\n\t\tthis.tip.offset = {\n\t\t\tx: x,\n\t\t\ty: y\n\t\t};\n\t}\n\n\tsetupComponents() { this.components = new Map(); }\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\t\tthis.data = this.prepareData(data);\n\t\tthis.calc(); // builds state\n\t\tthis.render(this.components, this.config.animate);\n\t\tthis.renderLegend();\n\t}\n\n\trender(components=this.components, animate=true) {\n\t\tif(this.config.isNavigable) {\n\t\t\t// Remove all existing overlays\n\t\t\tthis.overlays.map(o => o.parentNode.removeChild(o));\n\t\t\t// ref.parentNode.insertBefore(element, ref);\n\t\t}\n\t\tlet elementsToAnimate = [];\n\t\t// Can decouple to this.refreshComponents() first to save animation timeout\n\t\tcomponents.forEach(c => {\n\t\t\telementsToAnimate = elementsToAnimate.concat(c.update(animate));\n\t\t});\n\t\tif(elementsToAnimate.length > 0) {\n\t\t\trunSMILAnimation(this.container, this.svg, elementsToAnimate);\n\t\t\tsetTimeout(() => {\n\t\t\t\tcomponents.forEach(c => c.make());\n\t\t\t\tthis.updateNav();\n\t\t\t}, CHART_POST_ANIMATE_TIMEOUT);\n\t\t} else {\n\t\t\tcomponents.forEach(c => c.make());\n\t\t\tthis.updateNav();\n\t\t}\n\t}\n\n\tupdateNav() {\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.makeOverlay();\n\t\t\tthis.bindUnits();\n\t\t}\n\t}\n\n\trenderLegend() {}\n\n\tsetupNavigation(init=false) {\n\t\tif(!this.config.isNavigable) return;\n\n\t\tif(init) {\n\t\t\tthis.bindOverlay();\n\n\t\t\tthis.keyActions = {\n\t\t\t\t'13': this.onEnterKey.bind(this),\n\t\t\t\t'37': this.onLeftArrow.bind(this),\n\t\t\t\t'38': this.onUpArrow.bind(this),\n\t\t\t\t'39': this.onRightArrow.bind(this),\n\t\t\t\t'40': this.onDownArrow.bind(this),\n\t\t\t};\n\n\t\t\tdocument.addEventListener('keydown', (e) => {\n\t\t\t\tif(isElementInViewport(this.container)) {\n\t\t\t\t\te = e || window.event;\n\t\t\t\t\tif(this.keyActions[e.keyCode]) {\n\t\t\t\t\t\tthis.keyActions[e.keyCode]();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tmakeOverlay() {}\n\tupdateOverlay() {}\n\tbindOverlay() {}\n\tbindUnits() {}\n\n\tonLeftArrow() {}\n\tonRightArrow() {}\n\tonUpArrow() {}\n\tonDownArrow() {}\n\tonEnterKey() {}\n\n\taddDataPoint() {}\n\tremoveDataPoint() {}\n\n\tgetDataPoint() {}\n\tsetCurrentDataPoint() {}\n\n\tupdateDataset() {}\n\n\texport() {\n\t\tlet chartSvg = prepareForExport(this.svg);\n\t\tdownloadFile(this.title || 'Chart', [chartSvg]);\n\t}\n}\n","import BaseChart from './BaseChart';\nimport { truncateString } from '../utils/draw-utils';\nimport { legendDot } from '../utils/draw';\nimport { round } from '../utils/helpers';\nimport { getExtraWidth } from '../utils/constants';\n\nexport default class AggregationChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\n\t\tthis.config.formatTooltipY = (args.tooltipOptions || {}).formatTooltipY;\n\t\tthis.config.maxSlices = args.maxSlices || 20;\n\t\tthis.config.maxLegendPoints = args.maxLegendPoints || 20;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\t\tlet maxSlices = this.config.maxSlices;\n\t\ts.sliceTotals = [];\n\n\t\tlet allTotals = this.data.labels.map((label, i) => {\n\t\t\tlet total = 0;\n\t\t\tthis.data.datasets.map(e => {\n\t\t\t\ttotal += e.values[i];\n\t\t\t});\n\t\t\treturn [total, label];\n\t\t}).filter(d => { return d[0] >= 0; }); // keep only positive results\n\n\t\tlet totals = allTotals;\n\t\tif(allTotals.length > maxSlices) {\n\t\t\t// Prune and keep a grey area for rest as per maxSlices\n\t\t\tallTotals.sort((a, b) => { return b[0] - a[0]; });\n\n\t\t\ttotals = allTotals.slice(0, maxSlices-1);\n\t\t\tlet remaining = allTotals.slice(maxSlices-1);\n\n\t\t\tlet sumOfRemaining = 0;\n\t\t\tremaining.map(d => {sumOfRemaining += d[0];});\n\t\t\ttotals.push([sumOfRemaining, 'Rest']);\n\t\t\tthis.colors[maxSlices-1] = 'grey';\n\t\t}\n\n\t\ts.labels = [];\n\t\ttotals.map(d => {\n\t\t\ts.sliceTotals.push(round(d[0]));\n\t\t\ts.labels.push(d[1]);\n\t\t});\n\n\t\ts.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0);\n\n\t\tthis.center = {\n\t\t\tx: this.width / 2,\n\t\t\ty: this.height / 2\n\t\t};\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.state;\n\t\tthis.legendArea.textContent = '';\n\t\tthis.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);\n\n\t\tlet count = 0;\n\t\tlet y = 0;\n\t\tthis.legendTotals.map((d, i) => {\n\t\t\tlet barWidth = 150;\n\t\t\tlet divisor = Math.floor(\n\t\t\t\t(this.width - getExtraWidth(this.measures))/barWidth\n\t\t\t);\n\t\t\tif (this.legendTotals.length < divisor) {\n\t\t\t\tbarWidth = this.width/this.legendTotals.length;\n\t\t\t}\n\t\t\tif(count > divisor) {\n\t\t\t\tcount = 0;\n\t\t\t\ty += 20;\n\t\t\t}\n\t\t\tlet x = barWidth * count + 5;\n\t\t\tlet label = this.config.truncateLegends ? truncateString(s.labels[i], barWidth/10) : s.labels[i];\n\t\t\tlet formatted = this.config.formatTooltipY ? this.config.formatTooltipY(d) : d;\n\t\t\tlet dot = legendDot(\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\t5,\n\t\t\t\tthis.colors[i],\n\t\t\t\t`${label}: ${formatted}`,\n\t\t\t\tfalse\n\t\t\t);\n\t\t\tthis.legendArea.appendChild(dot);\n\t\t\tcount++;\n\t\t});\n\t}\n}\n","import AggregationChart from './AggregationChart';\nimport { getOffset } from '../utils/dom';\nimport { getComponent } from '../objects/ChartComponents';\nimport { PERCENTAGE_BAR_DEFAULT_HEIGHT, PERCENTAGE_BAR_DEFAULT_DEPTH } from '../utils/constants';\n\nexport default class PercentageChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'percentage';\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.barOptions = options.barOptions || {};\n\n\t\tlet b = this.barOptions;\n\t\tb.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT;\n\t\tb.depth = b.depth || PERCENTAGE_BAR_DEFAULT_DEPTH;\n\n\t\tm.paddings.right = 30;\n\t\tm.legendHeight = 60;\n\t\tm.baseHeight = (b.height + b.depth * 0.5) * 8;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'percentageBars',\n\t\t\t\t{\n\t\t\t\t\tbarHeight: this.barOptions.height,\n\t\t\t\t\tbarDepth: this.barOptions.depth,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xPositions,\n\t\t\t\t\t\twidths: s.widths,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\n\t\ts.xPositions = [];\n\t\ts.widths = [];\n\n\t\tlet xPos = 0;\n\t\ts.sliceTotals.map((value) => {\n\t\t\tlet width = this.width * value / s.grandTotal;\n\t\t\ts.widths.push(width);\n\t\t\ts.xPositions.push(xPos);\n\t\t\txPos += width;\n\t\t});\n\t}\n\n\tmakeDataByIndex() { }\n\n\tbindTooltip() {\n\t\tlet s = this.state;\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet bars = this.components.get('percentageBars').store;\n\t\t\tlet bar = e.target;\n\t\t\tif(bars.includes(bar)) {\n\n\t\t\t\tlet i = bars.indexOf(bar);\n\t\t\t\tlet gOff = getOffset(this.container), pOff = getOffset(bar);\n\n\t\t\t\tlet x = pOff.left - gOff.left + parseInt(bar.getAttribute('width'))/2;\n\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\tlet title = (this.formattedLabels && this.formattedLabels.length>0\n\t\t\t\t\t? this.formattedLabels[i] : this.state.labels[i]) + ': ';\n\t\t\t\tlet fraction = s.sliceTotals[i]/s.grandTotal;\n\n\t\t\t\tthis.tip.setValues(x, y, {name: title, value: (fraction*100).toFixed(1) + \"%\"});\n\t\t\t\tthis.tip.showTip();\n\t\t\t}\n\t\t});\n\t}\n}\n","import AggregationChart from './AggregationChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset } from '../utils/dom';\nimport { getPositionByAngle } from '../utils/helpers';\nimport { makeArcPathStr, makeCircleStr } from '../utils/draw';\nimport { lightenDarkenColor } from '../utils/colors';\nimport { transform } from '../utils/animation';\nimport { FULL_ANGLE } from '../utils/constants';\n\nexport default class PieChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'pie';\n\t\tthis.initTimeout = 0;\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\t\tthis.mouseMove = this.mouseMove.bind(this);\n\t\tthis.mouseLeave = this.mouseLeave.bind(this);\n\n\t\tthis.hoverRadio = args.hoverRadio || 0.1;\n\t\tthis.config.startAngle = args.startAngle || 0;\n\n\t\tthis.clockWise = args.clockWise || false;\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\t\tthis.radius = (this.height > this.width ? this.center.x : this.center.y);\n\n\t\tconst { radius, clockWise } = this;\n\n\t\tconst prevSlicesProperties = s.slicesProperties || [];\n\t\ts.sliceStrings = [];\n\t\ts.slicesProperties = [];\n\t\tlet curAngle = 180 - this.config.startAngle;\n\t\ts.sliceTotals.map((total, i) => {\n\t\t\tconst startAngle = curAngle;\n\t\t\tconst originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;\n\t\t\tconst largeArc = originDiffAngle > 180 ? 1: 0;\n\t\t\tconst diffAngle = clockWise ? -originDiffAngle : originDiffAngle;\n\t\t\tconst endAngle = curAngle = curAngle + diffAngle;\n\t\t\tconst startPosition = getPositionByAngle(startAngle, radius);\n\t\t\tconst endPosition = getPositionByAngle(endAngle, radius);\n\n\t\t\tconst prevProperty = this.init && prevSlicesProperties[i];\n\n\t\t\tlet curStart,curEnd;\n\t\t\tif(this.init) {\n\t\t\t\tcurStart = prevProperty ? prevProperty.startPosition : startPosition;\n\t\t\t\tcurEnd = prevProperty ? prevProperty.endPosition : startPosition;\n\t\t\t} else {\n\t\t\t\tcurStart = startPosition;\n\t\t\t\tcurEnd = endPosition;\n\t\t\t}\n\t\t\tconst curPath =\n\t\t\t\toriginDiffAngle === 360\n\t\t\t\t\t? makeCircleStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc)\n\t\t\t\t\t: makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc);\n\n\t\t\ts.sliceStrings.push(curPath);\n\t\t\ts.slicesProperties.push({\n\t\t\t\tstartPosition,\n\t\t\t\tendPosition,\n\t\t\t\tvalue: total,\n\t\t\t\ttotal: s.grandTotal,\n\t\t\t\tstartAngle,\n\t\t\t\tendAngle,\n\t\t\t\tangle: diffAngle\n\t\t\t});\n\n\t\t});\n\t\tthis.init = 0;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'pieSlices',\n\t\t\t\t{ },\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsliceStrings: s.sliceStrings,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalTranslateByAngle(property){\n\t\tconst{radius,hoverRadio} = this;\n\t\tconst position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);\n\t\treturn `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;\n\t}\n\n\thoverSlice(path,i,flag,e){\n\t\tif(!path) return;\n\t\tconst color = this.colors[i];\n\t\tif(flag) {\n\t\t\ttransform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));\n\t\t\tpath.style.fill = lightenDarkenColor(color, 50);\n\t\t\tlet g_off = getOffset(this.svg);\n\t\t\tlet x = e.pageX - g_off.left + 10;\n\t\t\tlet y = e.pageY - g_off.top - 10;\n\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t\t? this.formatted_labels[i] : this.state.labels[i]) + ': ';\n\t\t\tlet percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);\n\t\t\tthis.tip.setValues(x, y, {name: title, value: percent + \"%\"});\n\t\t\tthis.tip.showTip();\n\t\t} else {\n\t\t\ttransform(path,'translate3d(0,0,0)');\n\t\t\tthis.tip.hideTip();\n\t\t\tpath.style.fill = color;\n\t\t}\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', this.mouseMove);\n\t\tthis.container.addEventListener('mouseleave', this.mouseLeave);\n\t}\n\n\tmouseMove(e){\n\t\tconst target = e.target;\n\t\tlet slices = this.components.get('pieSlices').store;\n\t\tlet prevIndex = this.curActiveSliceIndex;\n\t\tlet prevAcitve = this.curActiveSlice;\n\t\tif(slices.includes(target)) {\n\t\t\tlet i = slices.indexOf(target);\n\t\t\tthis.hoverSlice(prevAcitve, prevIndex,false);\n\t\t\tthis.curActiveSlice = target;\n\t\t\tthis.curActiveSliceIndex = i;\n\t\t\tthis.hoverSlice(target, i, true, e);\n\t\t} else {\n\t\t\tthis.mouseLeave();\n\t\t}\n\t}\n\n\tmouseLeave(){\n\t\tthis.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);\n\t}\n}\n","import BaseChart from './BaseChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { makeText, heatSquare } from '../utils/draw';\nimport { DAY_NAMES_SHORT, addDays, areInSameMonth, getLastDateInMonth, setDayToSunday, getYyyyMmDd, getWeeksBetween, getMonthName, clone,\n\tNO_OF_MILLIS, NO_OF_YEAR_MONTHS, NO_OF_DAYS_IN_WEEK } from '../utils/date-utils';\nimport { calcDistribution, getMaxCheckpoint } from '../utils/intervals';\nimport { getExtraHeight, getExtraWidth, HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE,\n\tHEATMAP_GUTTER_SIZE } from '../utils/constants';\n\nconst COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;\nconst ROW_HEIGHT = COL_WIDTH;\n// const DAY_INCR = 1;\n\nexport default class Heatmap extends BaseChart {\n\tconstructor(parent, options) {\n\t\tsuper(parent, options);\n\t\tthis.type = 'heatmap';\n\n\t\tthis.countLabel = options.countLabel || '';\n\n\t\tlet validStarts = ['Sunday', 'Monday'];\n\t\tlet startSubDomain = validStarts.includes(options.startSubDomain)\n\t\t\t? options.startSubDomain : 'Sunday';\n\t\tthis.startSubDomainIndex = validStarts.indexOf(startSubDomain);\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.discreteDomains = options.discreteDomains === 0 ? 0 : 1;\n\n\t\tm.paddings.top = ROW_HEIGHT * 3;\n\t\tm.paddings.bottom = 0;\n\t\tm.legendHeight = ROW_HEIGHT * 2;\n\t\tm.baseHeight = ROW_HEIGHT * NO_OF_DAYS_IN_WEEK\n\t\t\t+ getExtraHeight(m);\n\n\t\tlet d = this.data;\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tthis.independentWidth = (getWeeksBetween(d.start, d.end)\n\t\t\t+ spacing) * COL_WIDTH + getExtraWidth(m);\n\t}\n\n\tupdateWidth() {\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tlet noOfWeeks = this.state.noOfWeeks ? this.state.noOfWeeks : 52;\n\t\tthis.baseWidth = (noOfWeeks + spacing) * COL_WIDTH\n\t\t\t+ getExtraWidth(this.measures);\n\t}\n\n\tprepareData(data=this.data) {\n\t\tif(data.start && data.end && data.start > data.end) {\n\t\t\tthrow new Error('Start date cannot be greater than end date.');\n\t\t}\n\n\t\tif(!data.start) {\n\t\t\tdata.start = new Date();\n\t\t\tdata.start.setFullYear( data.start.getFullYear() - 1 );\n\t\t}\n\t\tif(!data.end) { data.end = new Date(); }\n\t\tdata.dataPoints = data.dataPoints || {};\n\n\t\tif(parseInt(Object.keys(data.dataPoints)[0]) > 100000) {\n\t\t\tlet points = {};\n\t\t\tObject.keys(data.dataPoints).forEach(timestampSec => {\n\t\t\t\tlet date = new Date(timestampSec * NO_OF_MILLIS);\n\t\t\t\tpoints[getYyyyMmDd(date)] = data.dataPoints[timestampSec];\n\t\t\t});\n\t\t\tdata.dataPoints = points;\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\n\t\ts.start = clone(this.data.start);\n\t\ts.end = clone(this.data.end);\n\n\t\ts.firstWeekStart = clone(s.start);\n\t\ts.noOfWeeks = getWeeksBetween(s.start, s.end);\n\t\ts.distribution = calcDistribution(\n\t\t\tObject.values(this.data.dataPoints), HEATMAP_DISTRIBUTION_SIZE);\n\n\t\ts.domainConfigs = this.getDomains();\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\t\tlet lessCol = this.discreteDomains ? 0 : 1;\n\n\t\tlet componentConfigs = s.domainConfigs.map((config, i) => [\n\t\t\t'heatDomain',\n\t\t\t{\n\t\t\t\tindex: config.index,\n\t\t\t\tcolWidth: COL_WIDTH,\n\t\t\t\trowHeight: ROW_HEIGHT,\n\t\t\t\tsquareSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\tradius: this.rawChartArgs.radius || 0,\n\t\t\t\txTranslate: s.domainConfigs\n\t\t\t\t\t.filter((config, j) => j < i)\n\t\t\t\t\t.map(config => config.cols.length - lessCol)\n\t\t\t\t\t.reduce((a, b) => a + b, 0)\n\t\t\t\t\t* COL_WIDTH\n\t\t\t},\n\t\t\tfunction() {\n\t\t\t\treturn s.domainConfigs[i];\n\t\t\t}.bind(this)\n\n\t\t]);\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map((args, i) => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0] + '-' + i, component];\n\t\t\t})\n\t\t);\n\n\t\tlet y = 0;\n\t\tDAY_NAMES_SHORT.forEach((dayName, i) => {\n\t\t\tif([1, 3, 5].includes(i)) {\n\t\t\t\tlet dayText = makeText('subdomain-name', -COL_WIDTH/2, y, dayName,\n\t\t\t\t\t{\n\t\t\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\t\t\tdy: 8,\n\t\t\t\t\t\ttextAnchor: 'end'\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tthis.drawArea.appendChild(dayText);\n\t\t\t}\n\t\t\ty += ROW_HEIGHT;\n\t\t});\n\t}\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\n\t\tthis.data = this.prepareData(data);\n\t\tthis.draw();\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tthis.components.forEach(comp => {\n\t\t\t\tlet daySquares = comp.store;\n\t\t\t\tlet daySquare = e.target;\n\t\t\t\tif(daySquares.includes(daySquare)) {\n\n\t\t\t\t\tlet count = daySquare.getAttribute('data-value');\n\t\t\t\t\tlet dateParts = daySquare.getAttribute('data-date').split('-');\n\n\t\t\t\t\tlet month = getMonthName(parseInt(dateParts[1])-1, true);\n\n\t\t\t\t\tlet gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect();\n\n\t\t\t\t\tlet width = parseInt(e.target.getAttribute('width'));\n\t\t\t\t\tlet x = pOff.left - gOff.left + width/2;\n\t\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\t\tlet value = count + ' ' + this.countLabel;\n\t\t\t\t\tlet name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2];\n\n\t\t\t\t\tthis.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);\n\t\t\t\t\tthis.tip.showTip();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\trenderLegend() {\n\t\tthis.legendArea.textContent = '';\n\t\tlet x = 0;\n\t\tlet y = ROW_HEIGHT;\n\t\tlet radius = this.rawChartArgs.radius || 0;\n\n\t\tlet lessText = makeText('subdomain-name', x, y, 'Less',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tx = (COL_WIDTH * 2) + COL_WIDTH/2;\n\t\tthis.legendArea.appendChild(lessText);\n\n\t\tthis.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map((color, i) => {\n\t\t\tconst square = heatSquare('heatmap-legend-unit', x + (COL_WIDTH + 3) * i,\n\t\t\t\ty, HEATMAP_SQUARE_SIZE, radius, color);\n\t\t\tthis.legendArea.appendChild(square);\n\t\t});\n\n\t\tlet moreTextX = x + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH/4;\n\t\tlet moreText = makeText('subdomain-name', moreTextX, y, 'More',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tthis.legendArea.appendChild(moreText);\n\t}\n\n\tgetDomains() {\n\t\tlet s = this.state;\n\t\tconst [startMonth, startYear] = [s.start.getMonth(), s.start.getFullYear()];\n\t\tconst [endMonth, endYear] = [s.end.getMonth(), s.end.getFullYear()];\n\n\t\tconst noOfMonths = (endMonth - startMonth + 1) + (endYear - startYear) * 12;\n\n\t\tlet domainConfigs = [];\n\n\t\tlet startOfMonth = clone(s.start);\n\t\tfor(var i = 0; i < noOfMonths; i++) {\n\t\t\tlet endDate = s.end;\n\t\t\tif(!areInSameMonth(startOfMonth, s.end)) {\n\t\t\t\tlet [month, year] = [startOfMonth.getMonth(), startOfMonth.getFullYear()];\n\t\t\t\tendDate = getLastDateInMonth(month, year);\n\t\t\t}\n\t\t\tdomainConfigs.push(this.getDomainConfig(startOfMonth, endDate));\n\n\t\t\taddDays(endDate, 1);\n\t\t\tstartOfMonth = endDate;\n\t\t}\n\n\t\treturn domainConfigs;\n\t}\n\n\tgetDomainConfig(startDate, endDate='') {\n\t\tlet [month, year] = [startDate.getMonth(), startDate.getFullYear()];\n\t\tlet startOfWeek = setDayToSunday(startDate); // TODO: Monday as well\n\t\tendDate = clone(endDate) || getLastDateInMonth(month, year);\n\n\t\tlet domainConfig = {\n\t\t\tindex: month,\n\t\t\tcols: []\n\t\t};\n\n\t\taddDays(endDate, 1);\n\t\tlet noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate);\n\n\t\tlet cols = [], col;\n\t\tfor(var i = 0; i < noOfMonthWeeks; i++) {\n\t\t\tcol = this.getCol(startOfWeek, month);\n\t\t\tcols.push(col);\n\n\t\t\tstartOfWeek = new Date(col[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd);\n\t\t\taddDays(startOfWeek, 1);\n\t\t}\n\n\t\tif(col[NO_OF_DAYS_IN_WEEK - 1].dataValue !== undefined) {\n\t\t\taddDays(startOfWeek, 1);\n\t\t\tcols.push(this.getCol(startOfWeek, month, true));\n\t\t}\n\n\t\tdomainConfig.cols = cols;\n\n\t\treturn domainConfig;\n\t}\n\n\tgetCol(startDate, month, empty = false) {\n\t\tlet s = this.state;\n\n\t\t// startDate is the start of week\n\t\tlet currentDate = clone(startDate);\n\t\tlet col = [];\n\n\t\tfor(var i = 0; i < NO_OF_DAYS_IN_WEEK; i++, addDays(currentDate, 1)) {\n\t\t\tlet config = {};\n\n\t\t\t// Non-generic adjustment for entire heatmap, needs state\n\t\t\tlet currentDateWithinData = currentDate >= s.start && currentDate <= s.end;\n\n\t\t\tif(empty || currentDate.getMonth() !== month || !currentDateWithinData) {\n\t\t\t\tconfig.yyyyMmDd = getYyyyMmDd(currentDate);\n\t\t\t} else {\n\t\t\t\tconfig = this.getSubDomainConfig(currentDate);\n\t\t\t}\n\t\t\tcol.push(config);\n\t\t}\n\n\t\treturn col;\n\t}\n\n\tgetSubDomainConfig(date) {\n\t\tlet yyyyMmDd = getYyyyMmDd(date);\n\t\tlet dataValue = this.data.dataPoints[yyyyMmDd];\n\t\tlet config = {\n\t\t\tyyyyMmDd: yyyyMmDd,\n\t\t\tdataValue: dataValue || 0,\n\t\t\tfill: this.colors[getMaxCheckpoint(dataValue, this.state.distribution)]\n\t\t};\n\t\treturn config;\n\t}\n}\n","import BaseChart from './BaseChart';\nimport { dataPrep, zeroDataPrep, getShortenedLabels } from '../utils/axis-chart-utils';\nimport { AXIS_LEGEND_BAR_SIZE } from '../utils/constants';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset, fire } from '../utils/dom';\nimport { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale, getClosestInArray } from '../utils/intervals';\nimport { floatTwo } from '../utils/helpers';\nimport { makeOverlay, updateOverlay, legendBar } from '../utils/draw';\nimport { getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO,\n\tLINE_CHART_DOT_SIZE } from '../utils/constants';\n\nexport default class AxisChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\n\t\tthis.barOptions = args.barOptions || {};\n\t\tthis.lineOptions = args.lineOptions || {};\n\n\t\tthis.type = args.type || 'line';\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures() {\n\t\tif(this.data.datasets.length <= 1) {\n\t\t\tthis.config.showLegend = 0;\n\t\t\tthis.measures.paddings.bottom = 30;\n\t\t}\n\t}\n\n\tconfigure(options) {\n\t\tsuper.configure(options);\n\n\t\toptions.axisOptions = options.axisOptions || {};\n\t\toptions.tooltipOptions = options.tooltipOptions || {};\n\n\t\tthis.config.xAxisMode = options.axisOptions.xAxisMode || 'span';\n\t\tthis.config.yAxisMode = options.axisOptions.yAxisMode || 'span';\n\t\tthis.config.xIsSeries = options.axisOptions.xIsSeries || 0;\n\t\tthis.config.shortenYAxisNumbers = options.axisOptions.shortenYAxisNumbers || 0;\n\n\t\tthis.config.formatTooltipX = options.tooltipOptions.formatTooltipX;\n\t\tthis.config.formatTooltipY = options.tooltipOptions.formatTooltipY;\n\n\t\tthis.config.valuesOverPoints = options.valuesOverPoints;\n\t}\n\n\tprepareData(data=this.data) {\n\t\treturn dataPrep(data, this.type);\n\t}\n\n\tprepareFirstData(data=this.data) {\n\t\treturn zeroDataPrep(data);\n\t}\n\n\tcalc(onlyWidthChange = false) {\n\t\tthis.calcXPositions();\n\t\tif(!onlyWidthChange) {\n\t\t\tthis.calcYAxisParameters(this.getAllYValues(), this.type === 'line');\n\t\t}\n\t\tthis.makeDataByIndex();\n\t}\n\n\tcalcXPositions() {\n\t\tlet s = this.state;\n\t\tlet labels = this.data.labels;\n\t\ts.datasetLength = labels.length;\n\n\t\ts.unitWidth = this.width/(s.datasetLength);\n\t\t// Default, as per bar, and mixed. Only line will be a special case\n\t\ts.xOffset = s.unitWidth/2;\n\n\t\t// // For a pure Line Chart\n\t\t// s.unitWidth = this.width/(s.datasetLength - 1);\n\t\t// s.xOffset = 0;\n\n\t\ts.xAxis = {\n\t\t\tlabels: labels,\n\t\t\tpositions: labels.map((d, i) =>\n\t\t\t\tfloatTwo(s.xOffset + i * s.unitWidth)\n\t\t\t)\n\t\t};\n\t}\n\n\tcalcYAxisParameters(dataValues, withMinimum = 'false') {\n\t\tconst yPts = calcChartIntervals(dataValues, withMinimum);\n\t\tconst scaleMultiplier = this.height / getValueRange(yPts);\n\t\tconst intervalHeight = getIntervalSize(yPts) * scaleMultiplier;\n\t\tconst zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight);\n\n\t\tthis.state.yAxis = {\n\t\t\tlabels: yPts,\n\t\t\tpositions: yPts.map(d => zeroLine - d * scaleMultiplier),\n\t\t\tscaleMultiplier: scaleMultiplier,\n\t\t\tzeroLine: zeroLine,\n\t\t};\n\n\t\t// Dependent if above changes\n\t\tthis.calcDatasetPoints();\n\t\tthis.calcYExtremes();\n\t\tthis.calcYRegions();\n\t}\n\n\tcalcDatasetPoints() {\n\t\tlet s = this.state;\n\t\tlet scaleAll = values => values.map(val => scale(val, s.yAxis));\n\n\t\ts.datasets = this.data.datasets.map((d, i) => {\n\t\t\tlet values = d.values;\n\t\t\tlet cumulativeYs = d.cumulativeYs || [];\n\t\t\treturn {\n\t\t\t\tname: d.name && d.name.replace(/<|>|&/g, (char) => char == '&' ? '&' : char == '<' ? '<' : '>'),\n\t\t\t\tindex: i,\n\t\t\t\tchartType: d.chartType,\n\n\t\t\t\tvalues: values,\n\t\t\t\tyPositions: scaleAll(values),\n\n\t\t\t\tcumulativeYs: cumulativeYs,\n\t\t\t\tcumulativeYPos: scaleAll(cumulativeYs),\n\t\t\t};\n\t\t});\n\t}\n\n\tcalcYExtremes() {\n\t\tlet s = this.state;\n\t\tif(this.barOptions.stacked) {\n\t\t\ts.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos;\n\t\t\treturn;\n\t\t}\n\t\ts.yExtremes = new Array(s.datasetLength).fill(9999);\n\t\ts.datasets.map(d => {\n\t\t\td.yPositions.map((pos, j) => {\n\t\t\t\tif(pos < s.yExtremes[j]) {\n\t\t\t\t\ts.yExtremes[j] = pos;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tcalcYRegions() {\n\t\tlet s = this.state;\n\t\tif(this.data.yMarkers) {\n\t\t\tthis.state.yMarkers = this.data.yMarkers.map(d => {\n\t\t\t\td.position = scale(d.value, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\t// if(!d.label.includes(':')) {\n\t\t\t\t// \td.label += ': ' + d.value;\n\t\t\t\t// }\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.state.yRegions = this.data.yRegions.map(d => {\n\t\t\t\td.startPos = scale(d.start, s.yAxis);\n\t\t\t\td.endPos = scale(d.end, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t}\n\n\tgetAllYValues() {\n\t\tlet key = 'values';\n\n\t\tif(this.barOptions.stacked) {\n\t\t\tkey = 'cumulativeYs';\n\t\t\tlet cumulative = new Array(this.state.datasetLength).fill(0);\n\t\t\tthis.data.datasets.map((d, i) => {\n\t\t\t\tlet values = this.data.datasets[i].values;\n\t\t\t\td[key] = cumulative = cumulative.map((c, i) => c + values[i]);\n\t\t\t});\n\t\t}\n\n\t\tlet allValueLists = this.data.datasets.map(d => d[key]);\n\t\tif(this.data.yMarkers) {\n\t\t\tallValueLists.push(this.data.yMarkers.map(d => d.value));\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.data.yRegions.map(d => {\n\t\t\t\tallValueLists.push([d.end, d.start]);\n\t\t\t});\n\t\t}\n\n\t\treturn [].concat(...allValueLists);\n\t}\n\n\tsetupComponents() {\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'yAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.yAxisMode,\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tshortenNumbers: this.config.shortenYAxisNumbers\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'xAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.xAxisMode,\n\t\t\t\t\theight: this.height,\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\ts.xAxis.calcLabels = getShortenedLabels(this.width,\n\t\t\t\t\t\ts.xAxis.labels, this.config.xIsSeries);\n\n\t\t\t\t\treturn s.xAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'yRegions',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yRegions;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\t\t];\n\n\t\tlet barDatasets = this.state.datasets.filter(d => d.chartType === 'bar');\n\t\tlet lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');\n\n\t\tlet barsConfigs = barDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'barGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tstacked: this.barOptions.stacked,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t\tminHeight: this.height * MIN_BAR_PERCENT_HEIGHT,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet stacked = this.barOptions.stacked;\n\n\t\t\t\t\tlet spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO;\n\t\t\t\t\tlet barsWidth = s.unitWidth * (1 - spaceRatio);\n\t\t\t\t\tlet barWidth = barsWidth/(stacked ? 1 : barDatasets.length);\n\n\t\t\t\t\tlet xPositions = s.xAxis.positions.map(x => x - barsWidth/2);\n\t\t\t\t\tif(!stacked) {\n\t\t\t\t\t\txPositions = xPositions.map(p => p + barWidth * index);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet labels = new Array(s.datasetLength).fill('');\n\t\t\t\t\tif(this.config.valuesOverPoints) {\n\t\t\t\t\t\tif(stacked && d.index === s.datasets.length - 1) {\n\t\t\t\t\t\t\tlabels = d.cumulativeYs;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlabels = d.values;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet offsets = new Array(s.datasetLength).fill(0);\n\t\t\t\t\tif(stacked) {\n\t\t\t\t\t\toffsets = d.yPositions.map((y, j) => y - d.cumulativeYPos[j]);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: xPositions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\t\t\t\t\t\toffsets: offsets,\n\t\t\t\t\t\t// values: d.values,\n\t\t\t\t\t\tlabels: labels,\n\n\t\t\t\t\t\tzeroLine: s.yAxis.zeroLine,\n\t\t\t\t\t\tbarsWidth: barsWidth,\n\t\t\t\t\t\tbarWidth: barWidth,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet lineConfigs = lineDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'lineGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tsvgDefs: this.svgDefs,\n\t\t\t\t\theatline: this.lineOptions.heatline,\n\t\t\t\t\tregionFill: this.lineOptions.regionFill,\n\t\t\t\t\tspline: this.lineOptions.spline,\n\t\t\t\t\thideDots: this.lineOptions.hideDots,\n\t\t\t\t\thideLine: this.lineOptions.hideLine,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet minLine = s.yAxis.positions[0] < s.yAxis.zeroLine\n\t\t\t\t\t\t? s.yAxis.positions[0] : s.yAxis.zeroLine;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xAxis.positions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\n\t\t\t\t\t\tvalues: d.values,\n\n\t\t\t\t\t\tzeroLine: minLine,\n\t\t\t\t\t\tradius: this.lineOptions.dotSize || LINE_CHART_DOT_SIZE,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet markerConfigs = [\n\t\t\t[\n\t\t\t\t'yMarkers',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yMarkers;\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tcomponentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);\n\n\t\tlet optionals = ['yMarkers', 'yRegions'];\n\t\tthis.dataUnitComponents = [];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.filter(args => !optionals.includes(args[0]) || this.state[args[0]])\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\tif(args[0].includes('lineGraph') || args[0].includes('barGraph')) {\n\t\t\t\t\tthis.dataUnitComponents.push(component);\n\t\t\t\t}\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tmakeDataByIndex() {\n\t\tthis.dataByIndex = {};\n\n\t\tlet s = this.state;\n\t\tlet formatX = this.config.formatTooltipX;\n\t\tlet formatY = this.config.formatTooltipY;\n\t\tlet titles = s.xAxis.labels;\n\n\t\ttitles.map((label, index) => {\n\t\t\tlet values = this.state.datasets.map((set, i) => {\n\t\t\t\tlet value = set.values[index];\n\t\t\t\treturn {\n\t\t\t\t\ttitle: set.name,\n\t\t\t\t\tvalue: value,\n\t\t\t\t\tyPos: set.yPositions[index],\n\t\t\t\t\tcolor: this.colors[i],\n\t\t\t\t\tformatted: formatY ? formatY(value) : value,\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tthis.dataByIndex[index] = {\n\t\t\t\tlabel: label,\n\t\t\t\tformattedLabel: formatX ? formatX(label) : label,\n\t\t\t\txPos: s.xAxis.positions[index],\n\t\t\t\tvalues: values,\n\t\t\t\tyExtreme: s.yExtremes[index],\n\t\t\t};\n\t\t});\n\t}\n\n\tbindTooltip() {\n\t\t// NOTE: could be in tooltip itself, as it is a given functionality for its parent\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet m = this.measures;\n\t\t\tlet o = getOffset(this.container);\n\t\t\tlet relX = e.pageX - o.left - getLeftOffset(m);\n\t\t\tlet relY = e.pageY - o.top;\n\n\t\t\tif(relY < this.height + getTopOffset(m)\n\t\t\t\t&& relY > getTopOffset(m)) {\n\t\t\t\tthis.mapTooltipXPosition(relX);\n\t\t\t} else {\n\t\t\t\tthis.tip.hideTip();\n\t\t\t}\n\t\t});\n\t}\n\n\tmapTooltipXPosition(relX) {\n\t\tlet s = this.state;\n\t\tif(!s.yExtremes) return;\n\n\t\tlet index = getClosestInArray(relX, s.xAxis.positions, true);\n\t\tif (index >= 0) {\n\t\t\tlet dbi = this.dataByIndex[index];\n\n\t\t\tthis.tip.setValues(\n\t\t\t\tdbi.xPos + this.tip.offset.x,\n\t\t\t\tdbi.yExtreme + this.tip.offset.y,\n\t\t\t\t{name: dbi.formattedLabel, value: ''},\n\t\t\t\tdbi.values,\n\t\t\t\tindex\n\t\t\t);\n\n\t\t\tthis.tip.showTip();\n\t\t}\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.data;\n\t\tif(s.datasets.length > 1) {\n\t\t\tthis.legendArea.textContent = '';\n\t\t\ts.datasets.map((d, i) => {\n\t\t\t\tlet barWidth = AXIS_LEGEND_BAR_SIZE;\n\t\t\t\t// let rightEndPoint = this.baseWidth - this.measures.margins.left - this.measures.margins.right;\n\t\t\t\t// let multiplier = s.datasets.length - i;\n\t\t\t\tlet rect = legendBar(\n\t\t\t\t\t// rightEndPoint - multiplier * barWidth,\t// To right align\n\t\t\t\t\tbarWidth * i,\n\t\t\t\t\t'0',\n\t\t\t\t\tbarWidth,\n\t\t\t\t\tthis.colors[i],\n\t\t\t\t\td.name,\n\t\t\t\t\tthis.config.truncateLegends);\n\t\t\t\tthis.legendArea.appendChild(rect);\n\t\t\t});\n\t\t}\n\t}\n\n\n\n\t// Overlay\n\tmakeOverlay() {\n\t\tif(this.init) {\n\t\t\tthis.init = 0;\n\t\t\treturn;\n\t\t}\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\n\t\tthis.overlayGuides = this.dataUnitComponents.map(c => {\n\t\t\treturn {\n\t\t\t\ttype: c.unitType,\n\t\t\t\toverlay: undefined,\n\t\t\t\tunits: c.units,\n\t\t\t};\n\t\t});\n\n\t\tif(this.state.currentIndex === undefined) {\n\t\t\tthis.state.currentIndex = this.state.datasetLength - 1;\n\t\t}\n\n\t\t// Render overlays\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\n\t\t\td.overlay = makeOverlay[d.type](currentUnit);\n\t\t\tthis.drawArea.appendChild(d.overlay);\n\t\t});\n\t}\n\n\tupdateOverlayGuides() {\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\t}\n\n\tbindOverlay() {\n\t\tthis.parent.addEventListener('data-select', () => {\n\t\t\tthis.updateOverlay();\n\t\t});\n\t}\n\n\tbindUnits() {\n\t\tthis.dataUnitComponents.map(c => {\n\t\t\tc.units.map(unit => {\n\t\t\t\tunit.addEventListener('click', () => {\n\t\t\t\t\tlet index = unit.getAttribute('data-point-index');\n\t\t\t\t\tthis.setCurrentDataPoint(index);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\t// Note: Doesn't work as tooltip is absolutely positioned\n\t\tthis.tip.container.addEventListener('click', () => {\n\t\t\tlet index = this.tip.container.getAttribute('data-point-index');\n\t\t\tthis.setCurrentDataPoint(index);\n\t\t});\n\t}\n\n\tupdateOverlay() {\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\t\t\tupdateOverlay[d.type](currentUnit, d.overlay);\n\t\t});\n\t}\n\n\tonLeftArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex - 1);\n\t}\n\n\tonRightArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex + 1);\n\t}\n\n\tgetDataPoint(index=this.state.currentIndex) {\n\t\tlet s = this.state;\n\t\tlet data_point = {\n\t\t\tindex: index,\n\t\t\tlabel: s.xAxis.labels[index],\n\t\t\tvalues: s.datasets.map(d => d.values[index])\n\t\t};\n\t\treturn data_point;\n\t}\n\n\tsetCurrentDataPoint(index) {\n\t\tlet s = this.state;\n\t\tindex = parseInt(index);\n\t\tif(index < 0) index = 0;\n\t\tif(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1;\n\t\tif(index === s.currentIndex) return;\n\t\ts.currentIndex = index;\n\t\tfire(this.parent, \"data-select\", this.getDataPoint());\n\t}\n\n\n\n\t// API\n\taddDataPoint(label, datasetValues, index=this.state.datasetLength) {\n\t\tsuper.addDataPoint(label, datasetValues, index);\n\t\tthis.data.labels.splice(index, 0, label);\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\td.values.splice(index, 0, datasetValues[i]);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tremoveDataPoint(index = this.state.datasetLength-1) {\n\t\tif (this.data.labels.length <= 1) {\n\t\t\treturn;\n\t\t}\n\t\tsuper.removeDataPoint(index);\n\t\tthis.data.labels.splice(index, 1);\n\t\tthis.data.datasets.map(d => {\n\t\t\td.values.splice(index, 1);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tupdateDataset(datasetValues, index=0) {\n\t\tthis.data.datasets[index].values = datasetValues;\n\t\tthis.update(this.data);\n\t}\n\t// addDataset(dataset, index) {}\n\t// removeDataset(index = 0) {}\n\n\tupdateDatasets(datasets) {\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\tif(datasets[i]) {\n\t\t\t\td.values = datasets[i];\n\t\t\t}\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\t// updateDataPoint(dataPoint, index = 0) {}\n\t// addDataPoint(dataPoint, index = 0) {}\n\t// removeDataPoint(index = 0) {}\n}\n","import AggregationChart from './AggregationChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset } from '../utils/dom';\nimport { getPositionByAngle } from '../utils/helpers';\nimport { makeArcStrokePathStr, makeStrokeCircleStr } from '../utils/draw';\nimport { lightenDarkenColor } from '../utils/colors';\nimport { transform } from '../utils/animation';\nimport { FULL_ANGLE } from '../utils/constants';\n\nexport default class DonutChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'donut';\n\t\tthis.initTimeout = 0;\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\t\tthis.mouseMove = this.mouseMove.bind(this);\n\t\tthis.mouseLeave = this.mouseLeave.bind(this);\n\n\t\tthis.hoverRadio = args.hoverRadio || 0.1;\n\t\tthis.config.startAngle = args.startAngle || 0;\n\n\t\tthis.clockWise = args.clockWise || false;\n\t\tthis.strokeWidth = args.strokeWidth || 30;\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\t\tthis.radius =\n\t\t\tthis.height > this.width\n\t\t\t\t? this.center.x - this.strokeWidth / 2\n\t\t\t\t: this.center.y - this.strokeWidth / 2;\n\n\t\tconst { radius, clockWise } = this;\n\n\t\tconst prevSlicesProperties = s.slicesProperties || [];\n\t\ts.sliceStrings = [];\n\t\ts.slicesProperties = [];\n\t\tlet curAngle = 180 - this.config.startAngle;\n\n\t\ts.sliceTotals.map((total, i) => {\n\t\t\tconst startAngle = curAngle;\n\t\t\tconst originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;\n\t\t\tconst largeArc = originDiffAngle > 180 ? 1: 0;\n\t\t\tconst diffAngle = clockWise ? -originDiffAngle : originDiffAngle;\n\t\t\tconst endAngle = curAngle = curAngle + diffAngle;\n\t\t\tconst startPosition = getPositionByAngle(startAngle, radius);\n\t\t\tconst endPosition = getPositionByAngle(endAngle, radius);\n\n\t\t\tconst prevProperty = this.init && prevSlicesProperties[i];\n\n\t\t\tlet curStart,curEnd;\n\t\t\tif(this.init) {\n\t\t\t\tcurStart = prevProperty ? prevProperty.startPosition : startPosition;\n\t\t\t\tcurEnd = prevProperty ? prevProperty.endPosition : startPosition;\n\t\t\t} else {\n\t\t\t\tcurStart = startPosition;\n\t\t\t\tcurEnd = endPosition;\n\t\t\t}\n\t\t\tconst curPath =\n\t\t\t\toriginDiffAngle === 360\n\t\t\t\t\t? makeStrokeCircleStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc)\n\t\t\t\t\t: makeArcStrokePathStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc);\n\n\t\t\ts.sliceStrings.push(curPath);\n\t\t\ts.slicesProperties.push({\n\t\t\t\tstartPosition,\n\t\t\t\tendPosition,\n\t\t\t\tvalue: total,\n\t\t\t\ttotal: s.grandTotal,\n\t\t\t\tstartAngle,\n\t\t\t\tendAngle,\n\t\t\t\tangle: diffAngle\n\t\t\t});\n\n\t\t});\n\t\tthis.init = 0;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'donutSlices',\n\t\t\t\t{ },\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsliceStrings: s.sliceStrings,\n\t\t\t\t\t\tcolors: this.colors,\n\t\t\t\t\t\tstrokeWidth: this.strokeWidth,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalTranslateByAngle(property){\n\t\tconst{ radius, hoverRadio } = this;\n\t\tconst position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);\n\t\treturn `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;\n\t}\n\n\thoverSlice(path,i,flag,e){\n\t\tif(!path) return;\n\t\tconst color = this.colors[i];\n\t\tif(flag) {\n\t\t\ttransform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));\n\t\t\tpath.style.stroke = lightenDarkenColor(color, 50);\n\t\t\tlet g_off = getOffset(this.svg);\n\t\t\tlet x = e.pageX - g_off.left + 10;\n\t\t\tlet y = e.pageY - g_off.top - 10;\n\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t\t? this.formatted_labels[i] : this.state.labels[i]) + ': ';\n\t\t\tlet percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);\n\t\t\tthis.tip.setValues(x, y, {name: title, value: percent + \"%\"});\n\t\t\tthis.tip.showTip();\n\t\t} else {\n\t\t\ttransform(path,'translate3d(0,0,0)');\n\t\t\tthis.tip.hideTip();\n\t\t\tpath.style.stroke = color;\n\t\t}\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', this.mouseMove);\n\t\tthis.container.addEventListener('mouseleave', this.mouseLeave);\n\t}\n\n\tmouseMove(e){\n\t\tconst target = e.target;\n\t\tlet slices = this.components.get('donutSlices').store;\n\t\tlet prevIndex = this.curActiveSliceIndex;\n\t\tlet prevAcitve = this.curActiveSlice;\n\t\tif(slices.includes(target)) {\n\t\t\tlet i = slices.indexOf(target);\n\t\t\tthis.hoverSlice(prevAcitve, prevIndex,false);\n\t\t\tthis.curActiveSlice = target;\n\t\t\tthis.curActiveSliceIndex = i;\n\t\t\tthis.hoverSlice(target, i, true, e);\n\t\t} else {\n\t\t\tthis.mouseLeave();\n\t\t}\n\t}\n\n\tmouseLeave(){\n\t\tthis.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);\n\t}\n}\n"],"names":["styleInject","css","ref","insertAt","document","head","getElementsByTagName","style","createElement","type","firstChild","insertBefore","appendChild","styleSheet","cssText","createTextNode","$","expr","con","querySelector","getOffset","element","rect","getBoundingClientRect","top","documentElement","scrollTop","body","left","scrollLeft","isHidden","el","offsetParent","isElementInViewport","bottom","window","innerHeight","clientHeight","right","innerWidth","clientWidth","getElementContentWidth","styles","getComputedStyle","padding","parseFloat","paddingLeft","paddingRight","fire","target","properties","evt","createEvent","initEvent","j","dispatchEvent","getTopOffset","m","titleHeight","margins","paddings","getLeftOffset","getExtraHeight","legendHeight","getExtraWidth","floatTwo","d","toFixed","fillArray","array","count","start","length","fillerArray","Array","Math","abs","fill","concat","getStringWidth","string","charWidth","getPositionByAngle","angle","radius","sin","ANGLE_RATIO","cos","isValidNumber","candidate","nonNegative","Number","isNaN","undefined","isFinite","round","deepClone","cloned","value","key","Date","getTime","isArray","getBarHeightAndYAttr","yTop","zeroLine","height","y","equilizeNoOfElements","array1","array2","extraCount","truncateString","txt","len","slice","shortenLargeNumber","label","number","p","floor","log10","l","shortened","pow","getSplineCurvePointsStr","xList","yList","points","i","push","line","pointA","pointB","lengthX","lengthY","sqrt","atan2","controlPoint","current","previous","next","reverse","o","PI","command","reduce","acc","point","a","cps","cpe","limitColor","r","lightenDarkenColor","color","amt","col","getColor","usePound","num","parseInt","b","g","toString","isValidColor","RGB_RE","test","createSVG","tag","createElementNS","val","parentNode","keys","map","prop","setAttribute","renderVerticalGradient","svgDefElem","gradientId","setGradientStop","gradElem","offset","opacity","makeSVGContainer","parent","className","width","makeSVGDefs","svgContainer","makeSVGGroup","transform","args","inside","makePath","pathStr","makeArcPathStr","startPosition","endPosition","center","clockWise","largeArc","arcStartX","x","arcStartY","arcEndX","arcEndY","makeCircleStr","midArc","makeArcStrokePathStr","makeStrokeCircleStr","makeGradient","lighter","gradientDef","opacities","percentageBar","depth","PERCENTAGE_BAR_DEFAULT_DEPTH","heatSquare","size","data","legendBar","LABEL_MAX_CHARS","text","FONT_SIZE","FONT_FILL","group","legendDot","makeText","content","options","fontSize","dy","textAnchor","makeVertLine","y1","y2","stroke","BASE_LINE_COLOR","LABEL_MARGIN","makeHoriLine","x1","x2","lineType","shortenNumbers","yLine","pos","mode","AXIS_TICK_LENGTH","xLine","yMarker","labelPos","labelSvg","yRegion","region","datasetBar","index","meta","minHeight","datasetDot","dot","getPaths","pointsStr","join","spline","path","heatline","gradient_id","svgDefs","paths","regionFill","gradient_id_region","translate","unit","oldCoord","newCoord","duration","old","STD_EASING","translateVertLine","newX","oldX","MARKER_LINE_ANIM_DUR","translateHoriLine","newY","oldY","animateRegion","rectGroup","newY1","newY2","oldY2","newHeight","childNodes","stroke-dasharray","getAttribute","animateBar","bar","nodeName","UNIT_ANIM_DUR","split","animateDot","cx","cy","animatePath","newXList","newYList","pathComponents","animPath","PATH_ANIM_DUR","regStartPt","regEndPt","animRegion","animatePathStr","oldPath","animateSVGElement","props","dur","easingType","oldValues","animElement","cloneNode","newElement","attributeName","animateElement","currentValue","animAttr","EASING","webkitTransform","msTransform","mozTransform","oTransform","animateSVG","elements","newElements","animElements","replaceChild","animSvg","runSMILAnimation","svgElement","elementsToAnimate","animSvgElement","removeChild","REPLACE_ALL_NEW_DUR","downloadFile","filename","blob","Blob","url","URL","createObjectURL","href","download","click","revokeObjectURL","prepareForExport","svg","clone","classList","add","styleEl","create","CSSTEXT","container","innerHTML","treatAsUtc","date","result","setMinutes","getMinutes","getTimezoneOffset","getYyyyMmDd","dd","getDate","mm","getMonth","getFullYear","getWeeksBetween","startDate","endDate","weekStartDate","setDayToSunday","ceil","getDaysBetween","NO_OF_DAYS_IN_WEEK","millisecondsPerDay","SEC_IN_DAY","NO_OF_MILLIS","areInSameMonth","getMonthName","short","monthName","MONTH_NAMES","getLastDateInMonth","month","year","newDate","day","getDay","addDays","numberOfDays","setDate","getComponent","name","constants","getData","Object","componentConfigs","filter","includes","k","config","assign","ChartComponent","normalize","mantissa","exponent","sig","exp","getChartRangeIntervals","max","min","upperBound","lowerBound","range","noOfParts","partSize","intervals","getChartIntervals","maxValue","minValue","normalMaxValue","normalMinValue","calcChartIntervals","values","getPositiveFirstIntervals","absMinValue","intervalSize","unshift","withMinimum","pseudoMaxValue","pseudoMinValue","getZeroIndex","yPts","interval","getIntervalSize","indexOf","orderedArray","getValueRange","scale","yAxis","scaleMultiplier","getClosestInArray","goal","arr","closest","prev","curr","calcDistribution","distributionSize","dataMaxValue","distributionStep","distribution","checkpoint","getMaxCheckpoint","dataPrep","labels","datasetLength","datasets","zeroArray","vals","chartType","AXIS_DATASET_CHART_TYPES","yRegions","end","zeroDataPrep","realData","zeroData","yMarkers","getShortenedLabels","chartWidth","isSeries","allowedSpace","allowedLetters","DEFAULT_CHAR_WIDTH","seriesMultiple","maxLabelLength","getChartByType","AxisChart","chartTypes","error","BASE_MEASURES","INIT_CHART_UPDATE_TIMEOUT","CHART_POST_ANIMATE_TIMEOUT","DEFAULT_AXIS_CHART_TYPE","AXIS_LEGEND_BAR_SIZE","BAR_CHART_SPACE_RATIO","MIN_BAR_PERCENT_HEIGHT","LINE_CHART_DOT_SIZE","DOT_OVERLAY_SIZE_INCR","PERCENTAGE_BAR_DEFAULT_HEIGHT","HEATMAP_DISTRIBUTION_SIZE","HEATMAP_SQUARE_SIZE","HEATMAP_GUTTER_SIZE","TOOLTIP_POINTER_TRIANGLE_HEIGHT","DEFAULT_CHART_COLORS","HEATMAP_COLORS_GREEN","DEFAULT_COLORS","FULL_ANGLE","SvgTip","colors","titleName","titleValue","listValues","titleValueFirst","setup","makeTooltip","calcPosition","this","hideTip","title","dataPointList","addEventListener","set","_this2","formatted","li","offsetWidth","offsetHeight","maxLeft","pointer","pointerOffset","valueFirst","refresh","PRESET_COLOR_MAP","exec","c","ch","makeOverlay","transformValue","overlay","updateOverlay","attributes","attr","specified","nodeValue","BaseChart","HTMLElement","Error","rawChartArgs","prepareData","prepareFirstData","validateColors","isNavigable","animate","truncateLegends","measures","JSON","parse","stringify","setMeasures","showLegend","argHeight","baseHeight","state","initTimeout","overlays","configure","validColors","forEach","warn","boundDrawFn","_this","draw","ResizeObserver","resizeObserver","observe","disconnect","removeEventListener","makeContainer","updateWidth","independentWidth","tip","bindTooltip","onlyWidthChange","init","calc","makeChartArea","setupComponents","components","drawArea","render","update","renderLegend","setupNavigation","baseWidth","titleEL","titleFontSize","legendArea","updateTipOffset","Map","make","updateNav","bindUnits","bindOverlay","keyActions","onEnterKey","bind","onLeftArrow","onUpArrow","onRightArrow","onDownArrow","e","_this4","event","keyCode","chartSvg","AggregationChart","formatTooltipY","tooltipOptions","maxSlices","maxLegendPoints","s","sliceTotals","allTotals","total","totals","sort","sumOfRemaining","grandTotal","textContent","legendTotals","barWidth","divisor","_this3","NO_OF_YEAR_MONTHS","DAY_NAMES_SHORT","layerClass","layerTransform","makeElements","animateElements","store","layer","oldData","sliceStrings","strokeWidth","transition","newData","xPositions","widths","barHeight","barDepth","positions","position","newPos","newLabels","oldPos","oldLabels","calcLabels","_this5","newOptions","startPos","endPos","_this6","newStarts","oldStarts","colWidth","rowHeight","squareSize","xTranslate","serializedSubDomains","cols","week","weekNo","toUpperCase","yyyyMmDd","dataValue","square","unitType","units","yPositions","offsets","barsWidth","newXPos","newYPos","newOffsets","oldXPos","oldYPos","oldOffsets","hideLine","hideDots","valuesOverPoints","newValues","PercentageChart","barOptions","component","xPos","bars","get","gOff","pOff","formattedLabels","fraction","setValues","showTip","PieChart","mouseMove","mouseLeave","hoverRadio","startAngle","prevSlicesProperties","slicesProperties","curAngle","originDiffAngle","diffAngle","endAngle","prevProperty","curStart","curEnd","curPath","property","flag","calTranslateByAngle","g_off","pageX","pageY","formatted_labels","percent","slices","prevIndex","curActiveSliceIndex","prevAcitve","curActiveSlice","hoverSlice","COL_WIDTH","ROW_HEIGHT","Heatmap","countLabel","validStarts","startSubDomain","startSubDomainIndex","discreteDomains","spacing","noOfWeeks","setFullYear","dataPoints","timestampSec","firstWeekStart","domainConfigs","getDomains","lessCol","dayName","dayText","daySquares","comp","daySquare","dateParts","lessText","moreText","startMonth","startYear","noOfMonths","startOfMonth","getDomainConfig","startOfWeek","domainConfig","noOfMonthWeeks","getCol","empty","currentDate","currentDateWithinData","getSubDomainConfig","lineOptions","axisOptions","xAxisMode","yAxisMode","xIsSeries","shortenYAxisNumbers","formatTooltipX","calcXPositions","calcYAxisParameters","getAllYValues","makeDataByIndex","unitWidth","xOffset","xAxis","dataValues","intervalHeight","calcDatasetPoints","calcYExtremes","calcYRegions","scaleAll","cumulativeYs","replace","char","stacked","yExtremes","cumulativeYPos","cumulative","allValueLists","barDatasets","lineDatasets","barsConfigs","spaceRatio","lineConfigs","minLine","dotSize","markerConfigs","optionals","dataUnitComponents","dataByIndex","formatX","formatY","relX","relY","mapTooltipXPosition","dbi","yExtreme","formattedLabel","overlayGuides","currentIndex","currentUnit","_this7","setCurrentDataPoint","_this9","_this10","getDataPoint","datasetValues","splice","DonutChart","Chart"],"mappings":"YAAA,SAASA,aAAYC,EAAKC,OACX,KAARA,IAAiBA,KACtB,IAAIC,GAAWD,EAAIC,QAEnB,IAAKF,GAA2B,mBAAbG,UAAnB,CAEA,GAAIC,GAAOD,SAASC,MAAQD,SAASE,qBAAqB,QAAQ,GAC9DC,EAAQH,SAASI,cAAc,QACnCD,GAAME,KAAO,WAEI,QAAbN,GACEE,EAAKK,WACPL,EAAKM,aAAaJ,EAAOF,EAAKK,YAKhCL,EAAKO,YAAYL,GAGfA,EAAMM,WACRN,EAAMM,WAAWC,QAAUb,EAE3BM,EAAMK,YAAYR,SAASW,eAAed,KCvB9C,QAAgBe,GAAEC,EAAMC,SACA,gBAATD,IAAoBC,GAAOd,UAAUe,cAAcF,GAAQA,GAAQ,KA4ClF,QAAgBG,WAAUC,MACrBC,GAAOD,EAAQE,mCAKbD,EAAKE,KAAOpB,SAASqB,gBAAgBC,WAAatB,SAASuB,KAAKD,gBAC/DJ,EAAKM,MAAQxB,SAASqB,gBAAgBI,YAAczB,SAASuB,KAAKE,aAO1E,QAAgBC,UAASC,SACI,QAApBA,EAAGC,aAGZ,QAAgBC,qBAAoBF,MAE/BT,GAAOS,EAAGR,8BAGbD,GAAKE,KAAO,GACNF,EAAKM,MAAQ,GACbN,EAAKY,SAAWC,OAAOC,aAAehC,SAASqB,gBAAgBY,iBAC1DC,QAAUH,OAAOI,YAAcnC,SAASqB,gBAAgBe,aAIrE,QAAgBC,wBAAuBpB,MAClCqB,GAASP,OAAOQ,iBAAiBtB,GACjCuB,EAAUC,WAAWH,EAAOI,aAC/BD,WAAWH,EAAOK,oBAEZ1B,GAAQmB,YAAcI,EA2B9B,QAAgBI,MAAKC,EAAQxC,EAAMyC,MAC9BC,GAAM/C,SAASgD,YAAY,gBAE3BC,UAAU5C,GAAM,GAAM,OAErB,GAAI6C,KAAKJ,KACTI,GAAKJ,EAAWI,SAGdL,GAAOM,cAAcJ,GC7E7B,QAAgBK,cAAaC,SACrBA,GAAEC,YAAcD,EAAEE,QAAQnC,IAAMiC,EAAEG,SAASpC,IAGnD,QAAgBqC,eAAcJ,SACtBA,GAAEE,QAAQ/B,KAAO6B,EAAEG,SAAShC,KAGpC,QAAgBkC,gBAAeL,SACPA,GAAEE,QAAQnC,IAAMiC,EAAEE,QAAQzB,OAC9CuB,EAAEG,SAASpC,IAAMiC,EAAEG,SAAS1B,OAC5BuB,EAAEC,YAAcD,EAAEM,aAItB,QAAgBC,eAAcP,SACPA,GAAEE,QAAQ/B,KAAO6B,EAAEE,QAAQrB,MAC9CmB,EAAEG,SAAShC,KAAO6B,EAAEG,SAAStB,oHClDjC,QAAgB2B,UAASC,SACjBrB,YAAWqB,EAAEC,QAAQ,IAyC7B,QAAgBC,WAAUC,EAAOC,EAAOjD,MAASkD,0DAC5ClD,OACOkD,EAAQF,EAAM,GAAKA,EAAMA,EAAMG,OAAS,OAE/CC,GAAc,GAAIC,OAAMC,KAAKC,IAAIN,IAAQO,KAAKxD,YAC1CkD,EAAQE,EAAYK,OAAOT,GAASA,EAAMS,OAAOL,GAS1D,QAAgBM,gBAAeC,EAAQC,UAC9BD,EAAO,IAAIR,OAASS,EAyB7B,QAAgBC,oBAAmBC,EAAOC,YAErCT,KAAKU,IAAIF,EAAQG,aAAeF,IAChCT,KAAKY,IAAIJ,EAAQG,aAAeF,GASrC,QAAgBI,eAAcC,MAAWC,kEACpCC,OAAOC,MAAMH,SACMI,KAAdJ,MACCE,OAAOG,SAASL,MACjBC,GAAeD,EAAY,KAQrC,QAAgBM,OAAM7B,SAGdyB,QAAOhB,KAAKoB,MAAM7B,EAAI,MAAQ,OAOrC,QAAgB8B,WAAUP,MACtBQ,UAAQC,SAAOC,YAEfV,YAAqBW,YAChB,IAAIA,MAAKX,EAAUY,cAGH,qBAAdZ,wBAAAA,KAAwC,OAAdA,QAC5BA,KAGAf,MAAM4B,QAAQb,aAElBU,IAAOV,KACFA,EAAUU,KAEXA,GAAOH,UAAUE,SAGnBD,WC3IQM,sBAAqBC,EAAMC,MACtCC,UAAQC,eACRH,IAAQC,KACFA,EAAWD,IAChBA,MAEKA,EAAOC,IACZA,IAGGC,EAAQC,GAGjB,QAAgBC,sBAAqBC,EAAQC,MAC5CC,0DAAaD,EAAOtC,OAASqC,EAAOrC,aAGjCuC,GAAa,IACN3C,UAAUyC,EAAQE,KAElB3C,UAAU0C,EAAQC,IAEpBF,EAAQC,GAGjB,QAAgBE,gBAAeC,EAAKC,MAC9BD,QAGDA,GAAIzC,OAAS0C,EACTD,EAAIE,MAAM,EAAGD,EAAI,GAAK,MAEtBD,EAIT,QAAgBG,oBAAmBC,MAC9BC,aACiB,gBAAVD,GAAoBC,EAASD,MACnC,IAAqB,gBAAVA,OACN1B,OAAO0B,GACZ1B,OAAOC,MAAM0B,IAAS,MAAOD,MAI9BE,GAAI5C,KAAK6C,MAAM7C,KAAK8C,MAAM9C,KAAKC,IAAI0C,QACnCC,GAAK,EAAG,MAAOD,MACfI,GAAI/C,KAAK6C,MAAMD,EAAI,GACnBI,EAAahD,KAAKiD,IAAI,GAAIL,EAAQ,EAAJG,KAAWJ,EAAS3C,KAAKiD,IAAI,GAAIL,IAAIpD,QAAQ,SAGxEQ,MAAKoB,MAAgB,IAAV4B,GAAe,IAAM,KAAO,GAAI,IAAK,IAAK,IAAK,KAAKD,GAIvE,QAAgBG,yBAAwBC,EAAOC,OAG1C,GADAC,MACIC,EAAE,EAAEA,EAAEH,EAAMtD,OAAOyD,MACnBC,MAAMJ,EAAMG,GAAIF,EAAME,QAI1BE,GAAO,SAACC,EAAQC,MACfC,GAAUD,EAAO,GAAKD,EAAO,GAC7BG,EAAUF,EAAO,GAAKD,EAAO,iBAExBzD,KAAK6D,KAAK7D,KAAKiD,IAAIU,EAAS,GAAK3D,KAAKiD,IAAIW,EAAS,UACpD5D,KAAK8D,MAAMF,EAASD,KAIzBI,EAAe,SAACC,EAASC,EAAUC,EAAMC,MAGxCC,GAAIZ,EAFAS,GAAYD,EACZE,GAAQF,GAEZxD,EAAQ4D,EAAE5D,OAAS2D,EAAUnE,KAAKqE,GAAK,GACvCxE,EAfW,GAeFuE,EAAEvE,cACPmE,EAAQ,GAAKhE,KAAKY,IAAIJ,GAASX,EAC/BmE,EAAQ,GAAKhE,KAAKU,IAAIF,GAASX,UAUzB,UAACwD,EAAQiB,SAChBjB,GAAOkB,OAAO,SAACC,EAAKC,EAAOnB,EAAGoB,SAAY,KAANpB,EACrCmB,EAAM,OAAMA,EAAM,GAClBD,MAAOF,EAAQG,EAAOnB,EAAGoB,IAAM,KAGtBrB,EAZI,SAACoB,EAAOnB,EAAGoB,MAC1BC,GAAMZ,EAAaW,EAAEpB,EAAI,GAAIoB,EAAEpB,EAAI,GAAImB,GACvCG,EAAMb,EAAaU,EAAOC,EAAEpB,EAAI,GAAIoB,EAAEpB,EAAI,IAAI,cACtCqB,EAAI,OAAMA,EAAI,OAAMC,EAAI,OAAMA,EAAI,OAAMH,EAAM,OAAMA,EAAM,KCvExE,QAASI,YAAWC,SACfA,GAAI,IAAY,IACXA,EAAI,EAAU,EAChBA,EAGR,QAAgBC,oBAAmBC,EAAOC,MACrCC,GAAMC,SAASH,GACfI,GAAW,CACD,MAAVF,EAAI,OACDA,EAAI1C,MAAM,MACL,MAER6C,GAAMC,SAASJ,EAAI,IACnBJ,EAAID,YAAYQ,GAAO,IAAMJ,GAC7BM,EAAIV,YAAaQ,GAAO,EAAK,KAAUJ,GACvCO,EAAIX,YAAkB,IAANQ,GAAkBJ,UAC9BG,EAAS,IAAI,KAAOI,EAAKD,GAAK,EAAMT,GAAK,IAAKW,SAAS,IAGhE,QAAgBC,cAAarF,MAGxBsF,GAAS,mHADA,uCAECC,KAAKvF,IAAWsF,EAAOC,KAAKvF,GC7B3C,QAAShE,KAAEC,EAAMC,SACO,gBAATD,IAAoBC,GAAOd,UAAUe,cAAcF,GAAQA,GAAQ,KAGlF,QAAgBuJ,WAAUC,EAAK1B,MAC1B1H,GAAUjB,SAASsK,gBAAgB,6BAA8BD,OAEhE,GAAIxC,KAAKc,GAAG,IACZ4B,GAAM5B,EAAEd,MAEF,WAANA,MACD0C,GAAK/J,YAAYS,OAEf,IAAU,WAAN4G,EAAgB,IACpB/H,GAAMc,IAAE2J,KACRC,WAAWjK,aAAaU,EAASnB,KAC7BU,YAAYV,OAEJ,WAAN+H,EACQ,qBAAR0C,wBAAAA,YACFE,KAAKF,GAAKG,IAAI,cACZvK,MAAMwK,GAAQJ,EAAII,MAInB,cAAN9C,MAAyB,SACnB,cAANA,IACF,YAAyB0C,IAEjBK,aAAa/C,EAAG0C,UAKpBtJ,GAGR,QAAS4J,wBAAuBC,EAAYC,SACpCX,WAAU,yBACRU,KACJC,KACA,KACA,KACA,KACA,IAIN,QAASC,iBAAgBC,EAAUC,EAAQ3B,EAAO4B,SAC1Cf,WAAU,eACNa,uBACc1B,SACd2B,iBACMC,IAIlB,QAAgBC,kBAAiBC,EAAQC,EAAWC,EAAOjF,SACnD8D,WAAU,iBACLkB,SACHD,QACDE,SACCjF,IAIV,QAAgBkF,aAAYC,SACpBrB,WAAU,eACRqB,IAIV,QAAgBC,cAAaJ,MAAWK,0DAAU,GAAIN,6DAAO5F,GACxDmG,aACQN,YACAK,SAETN,KAAQO,EAAKC,OAASR,GAClBjB,UAAU,IAAKwB,GAWvB,QAAgBE,UAASC,SACjB3B,WAAU,yEAD0B,KAGvC2B,wEAHkD,mEAAa,6EAAoB,KAYxF,QAAgBC,gBAAeC,EAAeC,EAAaC,EAAQnH,MAAQoH,0DAAU,EAAGC,yDAAS,EAC3FC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAO5F,EAAI0F,EAAc1F,EAC9EkG,EAAqBN,EAAOI,EAAIL,EAAYK,EAAnCG,EAAsCP,EAAO5F,EAAI2F,EAAY3F,YAChE4F,EAAOI,MAAKJ,EAAO5F,YAC1B+F,MAAaE,aACZxH,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWC,OAGf,QAAgBC,eAAcV,EAAeC,EAAaC,EAAQnH,MAAQoH,0DAAU,EAAGC,yDAAS,EAC1FC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAO5F,EAAI0F,EAAc1F,EAC9EkG,EAA6BN,EAAOI,EAAIL,EAAYK,EAA3CK,EAAyD,EAAXT,EAAO5F,EAA7CmG,EAAoDP,EAAO5F,EAAI2F,EAAY3F,YACtF4F,EAAOI,MAAKJ,EAAO5F,YAC1B+F,MAAaE,aACZxH,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWG,cACVN,MAAaM,aACZ5H,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWC,OAGf,QAAgBG,sBAAqBZ,EAAeC,EAAaC,EAAQnH,MAAQoH,0DAAU,EAAGC,yDAAS,EACjGC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAO5F,EAAI0F,EAAc1F,EAC9EkG,EAAqBN,EAAOI,EAAIL,EAAYK,EAAnCG,EAAsCP,EAAO5F,EAAI2F,EAAY3F,YAEhE+F,MAAaE,aACnBxH,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWC,EAGf,QAAgBI,qBAAoBb,EAAeC,EAAaC,EAAQnH,MAAQoH,0DAAU,EAAGC,yDAAS,EAChGC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAO5F,EAAI0F,EAAc1F,EAC9EkG,EAA6BN,EAAOI,EAAIL,EAAYK,EAA3CK,EAAuD,EAAT5H,EAAawH,EAAnDE,EAA8DP,EAAO5F,EAAI0F,EAAc1F,YAElG+F,MAAaE,aACnBxH,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWG,YACVN,MAAaM,aACZ5H,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWC,EAGf,QAAgBK,cAAajC,EAAYvB,MAAOyD,2DAC3CjC,EAAY,sBAA6BxB,EAAQ,KAAMyD,EAAU,UAAY,WAC7EC,EAAcpC,uBAAuBC,EAAYC,GACjDmC,GAAa,EAAG,GAAK,UACtBF,QACW,GAAK,GAAK,oBAGRC,EAAa,KAAM1D,EAAO2D,EAAU,oBACpCD,EAAa,MAAO1D,EAAO2D,EAAU,oBACrCD,EAAa,OAAQ1D,EAAO2D,EAAU,IAE/CnC,EAGR,QAAgBoC,eAAcZ,EAAGhG,EAAGgF,EAAOjF,MAC1C8G,0DAAMC,6BAA8B5I,yDAAK,aAkBlC2F,WAAU,kBAfL,mBACRmC,IACAhG,QACIgF,SACCjF,OACF7B,iBAEK6E,mBAAmB7E,GAAO,8BAGV6B,EAASiF,QAAUA,OAAUjF,iBACvC8G,KAOnB,QAAgBE,YAAWhC,EAAWiB,EAAGhG,EAAGgH,EAAMvI,MAAQP,0DAAK,OAAQ+I,4DAClE5B,aACQN,IACRiB,IACAhG,QACIgH,SACCA,KACJvI,OACEP,iBAGAgG,KAAK+C,GAAM9C,IAAI,cAChB3E,GAAOyH,EAAKzH,KAGXqE,UAAU,OAAQwB,GAG1B,QAAgB6B,WAAUlB,EAAGhG,EAAGgH,MAAM9I,0DAAK,OAAQwC,yEAC/BL,eAAeK,EAAOyG,iBAAmBzG,KAExD2E,cACQ,eACR,IACA,QACI2B,SACC,WACF9I,GAEHkJ,EAAOvD,UAAU,kBACT,wBACR,IACA,KACc,EAAZwD,UAAiB,iBACI,IAAZA,UAAmB,mBAClB,aACTC,oBACK5G,IAGR6G,EAAQ1D,UAAU,4BACGmC,OAAMhG,iBAEzB/F,YAAY4J,UAAU,OAAQwB,MAC9BpL,YAAYmN,GAEXG,EAGR,QAAgBC,WAAUxB,EAAGhG,EAAGgH,MAAM9I,0DAAK,OAAQwC,yEAC/BL,eAAeK,EAAOyG,iBAAmBzG,KAExD2E,cACQ,gBACP,KACA,IACD2B,OACG9I,GAEHkJ,EAAOvD,UAAU,kBACT,wBACR,IACA,KACEwD,UAAa,QACbA,UAAU,EAAK,iBACM,IAAZA,UAAmB,mBAClB,aACTC,oBACK5G,IAGR6G,EAAQ1D,UAAU,4BACGmC,OAAMhG,iBAEzB/F,YAAY4J,UAAU,SAAUwB,MAChCpL,YAAYmN,GAEXG,EAGR,QAAgBE,UAAS1C,EAAWiB,EAAGhG,EAAG0H,MAASC,6DAC9CC,EAAWD,EAAQC,UAAYP,gBAI5BxD,WAAU,kBACLkB,IACRiB,IACAhG,UANoBd,KAAfyI,EAAQE,GAAmBF,EAAQE,GAAMD,EAAW,GAOnD,iBACIA,EAAW,UAPdD,EAAQzJ,MAAQoJ,wBACVK,EAAQG,YAAc,kBAS3BJ,IAIb,QAASK,cAAa/B,EAAGtF,EAAOsH,EAAIC,MAAIN,4DACnCA,GAAQO,SAAQP,EAAQO,OAASC,oBACjCpH,GAAI8C,UAAU,kBACN,iBAAmB8D,EAAQ5C,aAClC,KACA,KACAiD,KACAC,iBAEKN,EAAQO,UAIdd,EAAOvD,UAAU,UACjB,IACAmE,EAAKC,EAAKD,EAAKI,aAAeJ,EAAKI,aAAef,aACjDA,UAAY,iBACHA,UAAY,mBACV,mBACJ3G,EAAQ,KAGhBc,EAAOqC,UAAU,4BACKmC,oBAGrB/L,YAAY8G,KACZ9G,YAAYmN,GAEV5F,EAGR,QAAS6G,cAAarI,EAAGU,EAAO4H,EAAIC,MAAIZ,4DACnCA,GAAQO,SAAQP,EAAQO,OAASC,iBACjCR,EAAQa,WAAUb,EAAQa,SAAW,IACrCb,EAAQc,iBAAgB/H,EAAQD,mBAAmBC,OAKnDK,GAAI8C,UAAU,kBAHF,mBAAqB8D,EAAQ5C,WACtB,WAArB4C,EAAQa,SAAwB,SAAU,OAIvCF,KACAC,KACA,KACA,iBAEKZ,EAAQO,UAIdd,EAAOvD,UAAU,UACjByE,EAAKC,EAAKD,EAAKF,aAAeE,EAAKF,eACnC,KACEf,UAAY,EAAI,EAAK,iBACbA,UAAY,mBACViB,EAAKC,EAAK,MAAQ,kBACtB7H,EAAM,KAGdc,EAAOqC,UAAU,+BACO7D,uBACT,UAGP,KAAToH,GAAuB,MAATA,MACXxN,MAAMsO,OAAS,2BAGhBjO,YAAY8G,KACZ9G,YAAYmN,GAEV5F,EAGR,QAAgBkH,OAAM1I,EAAGU,EAAOsE,MAAO2C,4DACjC9I,eAAcmB,KAAIA,EAAI,GAEvB2H,EAAQgB,MAAKhB,EAAQgB,IAAM,QAC3BhB,EAAQhD,SAAQgD,EAAQhD,OAAS,GACjCgD,EAAQiB,OAAMjB,EAAQiB,KAAO,QAC7BjB,EAAQO,SAAQP,EAAQO,OAASC,iBACjCR,EAAQ5C,YAAW4C,EAAQ5C,UAAY,OAEvCuD,IAAM,EAAIO,iBACVN,EAAsB,SAAjBZ,EAAQiB,KAAkB5D,EAAQ6D,iBAAmB,QAE1C,SAAjBlB,EAAQiB,MAAmC,UAAhBjB,EAAQgB,QAChC3D,EAAQ6D,mBACR7D,MAKA2C,EAAQhD,UACRgD,EAAQhD,OAEP0D,aAAarI,EAAGU,EAAO4H,EAAIC,UACzBZ,EAAQO,iBACLP,EAAQ5C,mBACT4C,EAAQa,wBACFb,EAAQc,iBAI1B,QAAgBK,OAAM9C,EAAGtF,EAAOX,MAAQ4H,4DAClC9I,eAAcmH,KAAIA,EAAI,GAEvB2B,EAAQgB,MAAKhB,EAAQgB,IAAM,UAC3BhB,EAAQhD,SAAQgD,EAAQhD,OAAS,GACjCgD,EAAQiB,OAAMjB,EAAQiB,KAAO,QAC7BjB,EAAQO,SAAQP,EAAQO,OAASC,iBACjCR,EAAQ5C,YAAW4C,EAAQ5C,UAAY,OAavCiD,GAAKjI,EAAS8I,iBACdZ,EAAsB,SAAjBN,EAAQiB,MAAmB,EAAIC,iBAAmB9I,QAEvC,SAAjB4H,EAAQiB,MAAmC,QAAhBjB,EAAQgB,SAE/B,EAAIE,mBACL,GAGCd,aAAa/B,EAAGtF,EAAOsH,EAAIC,UACzBN,EAAQO,iBACLP,EAAQ5C,mBACT4C,EAAQa,WAIpB,QAAgBO,SAAQ/I,EAAGU,EAAOsE,MAAO2C,4DACpCA,GAAQqB,WAAUrB,EAAQqB,SAAW,YAIrCC,GAAWpF,UAAU,kBACb,gBAJiB,SAArB8D,EAAQqB,SAAsBZ,aACnCpD,EAAQ5G,eAAesC,EAAO,GAAK0H,eAKlC,KACEf,WAAa,EAAK,iBACVA,UAAY,mBACV,kBACJ3G,EAAM,KAGdc,EAAO6G,aAAarI,EAAG,GAAI,EAAGgF,UACzB2C,EAAQO,QAAUC,0BACfR,EAAQ5C,WAAa,YACtB4C,EAAQa,oBAGdvO,YAAYgP,GAEVzH,EAGR,QAAgB0H,SAAQlB,EAAIC,EAAIjD,EAAOtE,MAAOiH,6DAEzC5H,EAASiI,EAAKC,EAEdtN,EAAOkJ,UAAU,6EAIXsE,mCACenD,OAAUjF,KAG/B,IACA,QACIiF,SACCjF,GAGL4H,GAAQqB,WAAUrB,EAAQqB,SAAW,YAIrCC,GAAWpF,UAAU,kBACb,gBAJiB,SAArB8D,EAAQqB,SAAsBZ,aACnCpD,EAAQ5G,eAAesC,EAAM,GAAI,KAAO0H,eAKvC,KACEf,WAAa,EAAK,iBACVA,UAAY,mBACV,kBACJ3G,EAAM,KAGdyI,EAAStF,UAAU,+BACKoE,iBAGrBhO,YAAYU,KACZV,YAAYgP,GAEZE,EAGR,QAAgBC,YAAWpD,EAAGnG,EAAMmF,EAAOhC,MAAOtC,0DAAM,GAAI2I,yDAAM,EAAG1E,yDAAO,EAAG2E,8DAC5D1J,qBAAqBC,EAAMyJ,EAAKxJ,gCAA7CC,OAAQC,UACR2E,EAES,IAAX5E,MACOuJ,EAAKC,aACTD,EAAKC,WAIN1K,cAAcmH,KAAIA,EAAI,GACtBnH,cAAcmB,KAAIA,EAAI,GACtBnB,cAAckB,GAAQ,KAAOA,EAAS,GACtClB,cAAcmG,GAAO,KAAOA,EAAQ,MAErCrK,GAAOkJ,UAAU,4CAEJb,qBACIqG,IACjBrD,IACAhG,QACIgF,SACCjF,WAGA,KAEKW,EAAM7C,OAEb,GACDwG,aAAa,IAAK,KAClBA,aAAa,IAAK,MACnB+C,GAAOvD,UAAU,kBACT,qBACRmB,EAAM,IACN,KACEqC,UAAY,GAAK,EAAK,iBACdA,UAAY,mBACV,mBACJ3G,IAGR6G,EAAQ1D,UAAU,wBACDwF,yBACIrD,OAAMhG,iBAEzB/F,YAAYU,KACZV,YAAYmN,GAEXG,QArBA5M,GAyBT,QAAgB6O,YAAWxD,EAAGhG,EAAGvB,EAAQuE,MAAOtC,0DAAM,GAAI2I,yDAAM,EAC3DI,EAAM5F,UAAU,yBACHb,qBACIqG,KAChBrD,KACAhG,IACDvB,WAGK,KAEKiC,EAAM7C,OAEb,GACFwG,aAAa,KAAM,KACnBA,aAAa,KAAM,MAEnB+C,GAAOvD,UAAU,kBACT,qBACR,IACA,KACEwD,UAAY,GAAK,EAAI5I,EAAU,iBACvB4I,UAAY,mBACV,mBACJ3G,IAGR6G,EAAQ1D,UAAU,wBACDwF,yBACIrD,OAAMhG,iBAEzB/F,YAAYwP,KACZxP,YAAYmN,GAEXG,QAtBAkC,GA0BT,QAAgBC,UAASvI,EAAOC,EAAO4B,MAAO2E,6DAAY2B,4DAErDK,EADavI,EAAM+C,IAAI,SAACnE,EAAGsB,SAAOH,GAAMG,GAAK,IAAMtB,IAC5B4J,KAAK,IAG5BjC,GAAQkC,SACXF,EAAYzI,wBAAwBC,EAAOC,OAExC0I,GAAOvE,SAAS,IAAIoE,EAAW,kBAAmB3G,MAGnD2E,EAAQoC,SAAU,IAChBC,GAAcxD,aAAa8C,EAAKW,QAASjH,KACxCpJ,MAAMsO,eAAiB8B,SAGzBE,SACGJ,MAIJnC,EAAQwC,WAAY,IAClBC,GAAqB5D,aAAa8C,EAAKW,QAASjH,GAAO,GAEvDwC,EAAU,IAASrE,EAAM,OAAMmI,EAAKxJ,aAAc6J,MAAgBxI,EAAMX,OAAO,GAAG,OAAM8I,EAAKxJ,WAC3FqJ,OAAS5D,SAASC,gBAAwB,eAAgB4E,aAG1DF,GChmBR,QAAgBG,WAAUC,EAAMC,EAAUC,EAAUC,MAC/CC,GAA0B,gBAAbH,GAAwBA,EAAWA,EAASX,KAAK,aAEjEU,GACClF,UAAWoF,EAASZ,KAAK,OAC1Ba,EACAE,WACA,aACCvF,UAAWsF,IAId,QAAgBE,mBAAkB9B,EAAO+B,EAAMC,SACvCT,WAAUvB,GAAQgC,EAAM,IAAKD,EAAM,GAAIE,sBAG/C,QAAgBC,mBAAkBtC,EAAOuC,EAAMC,SACvCb,WAAU3B,GAAQ,EAAGwC,IAAQ,EAAGD,GAAOF,sBAG/C,QAAgBI,eAAcC,EAAWC,EAAOC,EAAOC,MAClDC,GAAYH,EAAQC,EACpB3Q,EAAOyQ,EAAUK,WAAW,WAG/B9Q,GACEoF,OAAQyL,EAAWE,mBAHV/Q,EAAKgR,aAAa,cAGyBH,GACtDT,qBACAJ,YAGeN,UAAUe,GAAY,EAAGG,IAAS,EAAGD,GAAQP,uBAI9D,QAAgBa,YAAWC,EAAK7F,EAAGnG,EAAMmF,MAAOL,0DAAO,IACpC/E,qBAAqBC,8DAAWC,kCAA7CC,OAAQC,iBACR2E,EACe,SAAjBkH,EAAIC,WACKD,EAAIJ,WAAW,IAGxBzG,MAAOA,EAAOjF,OAAQA,GACvBgM,cACApB,YAIeN,UAAUwB,EADRA,EAAIF,aAAa,aAAaK,MAAM,KAAK,GAAGxL,MAAM,GAAI,IAC3BwF,EAAGhG,GAAI+K,yBAG3Cc,GAAM7G,MAAOA,EAAOjF,OAAQA,EAAQiG,EAAGA,EAAGhG,EAAGA,GAAI+L,cAAepB,aAK3E,QAAgBsB,YAAWxC,EAAKzD,EAAGhG,SACd,WAAjByJ,EAAIqC,UAEUzB,UAAUZ,EADRA,EAAIkC,aAAa,aAAaK,MAAM,KAAK,GAAGxL,MAAM,GAAI,IAC3BwF,EAAGhG,GAAI+K,yBAG3CtB,GAAMyC,GAAIlG,EAAGmG,GAAInM,GAAI+L,cAAepB,aAK/C,QAAgByB,aAAYlC,EAAOmC,EAAUC,EAAUxM,EAAU+J,MAC5D0C,MACA5C,EAAY2C,EAASnI,IAAI,SAACnE,EAAGsB,SAAO+K,GAAS/K,GAAK,IAAMtB,IAAI4J,KAAK,IAEjEC,KACHF,EAAYzI,wBAAwBmL,EAAUC,OAEzCE,IAAYtC,EAAMJ,MAAOvM,EAAE,IAAMoM,GAAY8C,cAAe9B,iBACnDpJ,KAAKiL,GAEjBtC,EAAMf,OAAQ,IACZuD,GAAgBL,EAAS,OAAMvM,MAC/B6M,MAAeN,EAAS7L,OAAO,GAAG,QAAOV,EAEvC8M,GACL1C,EAAMf,QACL5L,EAAE,IAAMmP,EAAa/C,EAAYgD,GAClCF,cACA9B,cAEcpJ,KAAKqL,SAGdL,GAGR,QAAgBM,gBAAeC,EAAStH,UAC/BsH,GAAUvP,EAAGiI,GAAUuG,cAAepB,uJC1F/C,QAASoC,mBAAkBrS,EAASsS,EAAOC,MAAKC,0DAAW,SAAUpT,6DAAKoF,GAAWiO,4DAEhFC,EAAc1S,EAAQ2S,WAAU,GAChCC,EAAa5S,EAAQ2S,WAAU,OAE/B,GAAIE,KAAiBP,GAAO,IAC3BQ,YACiB,cAAlBD,EACe9T,SAASsK,gBAAgB,6BAA8B,oBAEvDtK,SAASsK,gBAAgB,6BAA8B,cAErE0J,GAAeN,EAAUI,IAAkB7S,EAAQiR,aAAa4B,GAChEhO,EAAQyN,EAAMO,GAEdG,iBACYH,OACTE,KACFlO,QACG,SACF0N,EAAI,IAAO,WACRQ,EAAe,IAAMlO,aACjBoO,OAAOT,YACT,eACA,cACJ,SAGJpT,OACF,KAAmBA,OAGf,GAAIwH,KAAKoM,KACErJ,aAAa/C,EAAGoM,EAASpM,MAG7BrH,YAAYuT,GAErB1T,IACSuK,aAAakJ,eAA4BhO,SAEzC8E,aAAakJ,EAAehO,UAIjC6N,EAAaE,GAGtB,QAAgBlI,WAAU1K,EAASd,KAC1BA,MAAMwL,UAAYxL,IAClBA,MAAMgU,gBAAkBhU,IACxBA,MAAMiU,YAAcjU,IACpBA,MAAMkU,aAAelU,IACrBA,MAAMmU,WAAanU,EAG5B,QAASoU,YAAW9I,EAAc+I,MAC7BC,MACAC,OAEKhK,IAAI,eACRmG,GAAO5P,EAAQ,GACfoK,EAASwF,EAAKrG,WAEdmJ,SAAaE,WAET,GAAKhD,QACeyC,oDAAqBrS,4CAErC6G,KAAK+L,KACJ/L,MAAM6L,EAAatI,IAE5BA,KACIsJ,aAAahB,EAAa9C,QAI/B+D,GAAUnJ,EAAamI,WAAU,YAExBlJ,IAAI,SAACiJ,EAAa9L,GAC1B8L,EAAY,OACH,GAAGgB,aAAaF,EAAY5M,GAAI8L,EAAY,MAC/C9L,GAAG,GAAK4M,EAAY5M,MAIxB+M,EAGR,QAAgBC,kBAAiBxJ,EAAQyJ,EAAYC,MACpB,IAA7BA,EAAkB3Q,WAEjB4Q,GAAiBT,WAAWO,EAAYC,EACzCD,GAAWtK,YAAca,MACpB4J,YAAYH,KACZtU,YAAYwU,eAKT,WACPA,EAAexK,YAAca,MACxB4J,YAAYD,KACZxU,YAAYsU,KAElBI,sBCnHG,QAASC,cAAaC,EAAU5H,MAClCvE,GAAIjJ,SAASI,cAAc,OAC7BD,MAAQ,mBACNkV,GAAO,GAAIC,MAAK9H,GAAOnN,KAAM,iCAC7BkV,EAAMxT,OAAOyT,IAAIC,gBAAgBJ,KACnCK,KAAOH,IACPI,SAAWP,WACJ7T,KAAKf,YAAYyI,KACxB2M,mBACS,oBACDrU,KAAK0T,YAAYhM,UACnBuM,IAAIK,gBAAgBN,IACzB,KAGJ,QAAgBO,kBAAiBC,MAC5BC,GAAQD,EAAInC,WAAU,KACpBqC,UAAUC,IAAI,qBACdtL,aAAa,QAAS,gCACtBA,aAAa,cAAe,mCAC9BuL,GAAUvV,EAAEwV,OAAO,mBACTC,YAER9V,aAAa4V,EAASH,EAAM1V,eAE9BgW,GAAY1V,EAAEwV,OAAO,gBACf5V,YAAYwV,GAEfM,EAAUC,yuBCblB,QAASC,YAAWC,MACfC,GAAS,GAAI1Q,MAAKyQ,YACfE,WAAWD,EAAOE,aAAeF,EAAOG,qBACxCH,EAGR,QAAgBI,aAAYL,MACvBM,GAAKN,EAAKO,UACVC,EAAKR,EAAKS,WAAa,SAE1BT,EAAKU,eACJF,EAAG,EAAI,GAAK,KAAOA,GACnBF,EAAG,EAAI,GAAK,KAAOA,GACnB5G,KAAK,KAGR,QAAgB6F,OAAMS,SACd,IAAIzQ,MAAKyQ,EAAKxQ,WAiBtB,QAAgBmR,iBAAgBC,EAAWC,MACtCC,GAAgBC,eAAeH,SAC5B9S,MAAKkT,KAAKC,eAAeH,EAAeD,GAAWK,oBAG3D,QAAgBD,gBAAeL,EAAWC,MACrCM,GAAqBC,WAAaC,oBAC9BtB,WAAWc,GAAWd,WAAWa,IAAcO,EAGxD,QAAgBG,gBAAeV,EAAWC,SAClCD,GAAUH,aAAeI,EAAQJ,YACpCG,EAAUF,gBAAkBG,EAAQH,cAGzC,QAAgBa,cAAanQ,MAAGoQ,2DAC3BC,EAAYC,YAAYtQ,SACrBoQ,GAAQC,EAAUnR,MAAM,EAAG,GAAKmR,EAGxC,QAAgBE,oBAAoBC,EAAOC,SACnC,IAAItS,MAAKsS,EAAMD,EAAQ,EAAG,GAIlC,QAAgBb,gBAAef,MAC1B8B,GAAUvC,MAAMS,GACd+B,EAAMD,EAAQE,eACT,KAARD,WACMD,GAAW,EAAKC,GAElBD,EAIR,QAAgBG,SAAQjC,EAAMkC,KACxBC,QAAQnC,EAAKO,UAAY2B,iHC6V/B,QAAgBE,cAAaC,EAAMC,EAAWC,MACzCvO,GAAOwO,OAAOxO,KAAKyO,kBAAkBC,OAAO,kBAAKL,GAAKM,SAASC,KAC/DC,EAASJ,iBAAiBzO,EAAK,kBAC5B8O,OAAOD,aACFP,UACFC,IAEH,GAAIQ,gBAAeF,goDC5b3B,QAESG,WAAUlN,MAKX,IAAJA,SACM,EAAG,MAET/G,MAAM+G,UACAmN,UAAW,iBAAkBC,SAAU,QAE5CC,GAAMrN,EAAI,EAAI,GAAK,MACnB7G,SAAS6G,UACJmN,SAAgB,iBAANE,EAAwBD,SAAU,OAGjDpV,KAAKC,IAAI+H,MACTsN,GAAMtV,KAAK6C,MAAM7C,KAAK8C,MAAMkF,WAGxBqN,GAFErN,EAAEhI,KAAKiD,IAAI,GAAIqS,IAENA,GAGpB,QAASC,wBAAuBC,MAAKC,0DAAI,EACpCC,EAAa1V,KAAKkT,KAAKsC,GACvBG,EAAa3V,KAAK6C,MAAM4S,GACxBG,EAAQF,EAAaC,EAErBE,EAAYD,EACZE,EAAW,CAGZF,GAAQ,IACPA,EAAQ,GAAM,UAGKD,KAEVC,EAAM,IACP,GAITA,GAAS,MAEAA,KADC,IAKA,IAAVA,MACU,IACD,OAIR,GADAG,MACIzS,EAAI,EAAGA,GAAKuS,EAAWvS,MACpBC,KAAKoS,EAAaG,EAAWxS,SAEjCyS,GAGR,QAASC,mBAAkBC,MAAUC,0DAAS,IACZhB,UAAUe,2BAAtCE,OAAgBf,OACjBgB,EAAiBF,EAAWA,EAASlW,KAAKiD,IAAI,GAAImS,GAAW,EAK7DW,EAAYR,yBAFCY,EAAe3W,QAAQ,GAEe4W,YAC3CL,EAAU5P,IAAI,kBAAS5E,GAAQvB,KAAKiD,IAAI,GAAImS,KAIzD,QAAgBiB,oBAAmBC,WAYzBC,GAA0BN,EAAUO,OAOxC,GANAT,GAAYC,kBAAkBC,GAE9BQ,EAAeV,EAAU,GAAKA,EAAU,GAGxCxU,EAAQ,EACJ+B,EAAI,EAAG/B,EAAQiV,EAAalT,OAC1BmT,IACCC,SAAU,EAAKnV,SAEnBwU,MAvBkCY,2DAMtCV,EAAWjW,KAAKwV,oCAAOc,IACvBJ,EAAWlW,KAAKyV,oCAAOa,IAGTP,QAkBfE,GAAY,GAAKC,GAAY,EACpBhB,UAAUe,GAAU,KAC3BU,EAGSX,kBAAkBC,EAAUC,GAF5BF,kBAAkBC,OAQ3B,IAAGA,EAAW,GAAKC,EAAW,EAAG,IAOjCM,GAAcxW,KAAKC,IAAIiW,EAExBD,IAAYO,GACHtB,UAAUe,GAAU,KACnBM,EAA0BN,EAAUO,KAGrCtB,UAAUsB,GAAa,KACfD,EAA0BC,EAAaP,GACjC9R,UAAUgC,IAAI,mBAAW,EAAN5G,SAOzC,IAAG0W,GAAY,GAAKC,GAAY,EAAG,IAInCU,GAAiB5W,KAAKC,IAAIiW,GAC1BW,EAAiB7W,KAAKC,IAAIgW,EAEnBf,WAAU0B,GAAgB,QACjCD,EAGSX,kBAAkBY,EAAgBC,GAFlCb,kBAAkBY,IAKTzS,UAAUgC,IAAI,mBAAW,EAAN5G,UAGnCwW,GAGR,QAAgBe,cAAaC,MAExBC,GAAWC,gBAAgBF,SAC5BA,GAAKG,QAAQ,IAAM,EAGTH,EAAKG,QAAQ,GAChBH,EAAK,GAAK,GAIL,EADJA,EAAK,GACUC,GAKX,EADJD,EAAKA,EAAKlX,OAAS,GACJmX,GAAYD,EAAKlX,OAAS,GAiBrD,QAAgBoX,iBAAgBE,SACxBA,GAAa,GAAKA,EAAa,GAGvC,QAAgBC,eAAcD,SACtBA,GAAaA,EAAatX,OAAO,GAAKsX,EAAa,GAG3D,QAAgBE,OAAMrR,EAAKsR,SACnBhY,UAASgY,EAAMxV,SAAWkE,EAAMsR,EAAMC,iBAY9C,QAAgBC,mBAAkBC,EAAMC,MAAKrM,2DACxCsM,EAAUD,EAAInT,OAAO,SAASqT,EAAMC,SAC/B7X,MAAKC,IAAI4X,EAAOJ,GAAQzX,KAAKC,IAAI2X,EAAOH,GAAQI,EAAOD,aAGzDvM,GAAQqM,EAAIR,QAAQS,GAAWA,EAGvC,QAAgBG,kBAAiBxB,EAAQyB,OASpC,GALAC,GAAehY,KAAKwV,oCAAOc,IAE3B2B,EAAmB,GAAKF,EAAmB,GAC3CG,KAEI5U,EAAI,EAAGA,EAAIyU,EAAkBzU,IAAK,IACrC6U,GAAaH,GAAgBC,EAAmB3U,KACvCC,KAAK4U,SAGZD,GAGR,QAAgBE,kBAAiB7W,EAAO2W,SAChCA,GAAatD,OAAO,kBAAKrV,GAAIgC,IAAO1B,84BC7O5C,QAGgBwY,UAASpP,EAAMnN,KACzBwc,OAASrP,EAAKqP,cAEfC,GAAgBtP,EAAKqP,OAAOzY,OAG5B2Y,EAAWvP,EAAKuP,SAChBC,EAAY,GAAI1Y,OAAMwY,GAAerY,KAAK,SAC1CsY,gBAGMC,OAIDtS,IAAI,eAER5G,EAAE+W,OAEC,IAEFoC,GAAOnZ,EAAE+W,YACNoC,EAAKvS,IAAI,kBAASlF,OAAM+E,GAAa,EAANA,KAG9BnG,OAAS0Y,EACTG,EAAKlW,MAAM,EAAG+V,GAEd9Y,UAAUiZ,EAAMH,EAAgBG,EAAK7Y,OAAQ,KAEnDyW,OAASoC,SAZTpC,OAASmC,CAgBRlZ,GAAEoZ,YACDC,yBAAyB/D,SAAS/Y,KACpC6c,UAAY7c,KASbmN,EAAK4P,YACFA,SAAS1S,IAAI,eACd5G,EAAEuZ,IAAMvZ,EAAEK,MAAO,QACCL,EAAEuZ,IAAKvZ,EAAEK,SAA1BA,aAASkZ,YAKR7P,EAGR,QAAgB8P,cAAaC,MACxBT,GAAgBS,EAASV,OAAOzY,OAChC4Y,EAAY,GAAI1Y,OAAMwY,GAAerY,KAAK,GAE1C+Y,UACKD,EAASV,OAAO9V,MAAM,GAAI,YACxBwW,EAASR,SAASrS,IAAI,wBAExB,UACEsS,EAAUjW,MAAM,GAAI,aACjBjD,EAAEoZ,oBAKbK,GAASE,aACFA,iBAEA,QACA,MAKPF,EAASH,aACFA,iBAEA,MACF,QACE,MAKHI,EAGR,QAAgBE,oBAAmBC,MAAYd,6DAAWe,6DACrDC,EAAeF,EAAad,EAAOzY,MACpCyZ,IAAgB,IAAGA,EAAe,MACjCC,GAAiBD,EAAeE,mBAEhCC,YACDJ,EAAU,IAERK,GAAiB1Z,KAAKwV,oCAAO8C,EAAOnS,IAAI,kBAASzD,GAAM7C,aAC1CG,KAAKkT,KAAKwG,EAAeH,SAG1BjB,GAAOnS,IAAI,SAACzD,EAAOY,aAC1B,IACAzD,OAAS0Z,IAEbF,EAOA/V,EAAImW,GAAmB,MACjB,MAPNF,EAAe,EAAI,EACb7W,EAAMF,MAAM,EAAG+W,EAAe,GAAK,OAEnC7W,EAAMF,MAAM,EAAG+W,GAAkB,MAQrC7W,wmDCzGT,QAASiX,qBAAehB,0DAAY,OAAQ7R,eAAQ6C,qBACjC,eAAdgP,KACK7c,KAAO,OACR,GAAI8d,WAAU9S,EAAQ6C,IAGzBkQ,WAAWlB,GAKT,GAAIkB,YAAWlB,GAAW7R,EAAQ6C,gBAJhCmQ,MAAM,yBAA2BnB,shEbZ3Ctc,GAAEwV,OAAS,SAAC/L,EAAK1B,MACZ1H,GAAUjB,SAASI,cAAciK,OAEhC,GAAIxC,KAAKc,GAAG,IACZ4B,GAAM5B,EAAEd,MAEF,WAANA,IACD0C,GAAK/J,YAAYS,OAEf,IAAU,WAAN4G,EAAgB,IACpB/H,GAAMc,EAAE2J,KACRC,WAAWjK,aAAaU,EAASnB,KAC7BU,YAAYV,OAEJ,WAAN+H,EACQ,qBAAR0C,sBAAAA,YACFE,KAAKF,GAAKG,IAAI,cACZvK,MAAMwK,GAAQJ,EAAII,KAGlB9C,IAAK5G,KACP4G,GAAK0C,IAGLK,aAAa/C,EAAG0C,SAInBtJ,GCxBD,IAAMqd,6BAEN,UACG,QACF,SACC,kBAGF,UACG,QACF,SACC,eAGI,gBACC,gBACC,iBAEC,IAyBHC,0BAA4B,IAC5BC,2BAA6B,IAE7BC,wBAA0B,OAC1BtB,0BAA4B,OAAQ,OAEpCuB,qBAAuB,IAEvBC,sBAAwB,GACxBC,uBAAyB,EAEzBC,oBAAsB,EACtBC,sBAAwB,EAExBC,8BAAgC,GAChC1R,6BAA+B,EAI/B2R,0BAA4B,EAE5BC,oBAAsB,GACtBC,oBAAsB,EAEtBnB,mBAAqB,EAErBoB,gCAAkC,EAEzCC,sBAAwB,aAAc,OAAQ,SAAU,MAAO,SACpE,SAAU,QAAS,cAAe,SAAU,UAAW,aAAc,aAChEC,sBAAwB,UAAW,UAAW,UAAW,UAAW,WAI7DC,oBACPF,0BACCA,yBACDA,gCACOA,6BACHC,2BACFD,sBAIKla,YAAcX,KAAKqE,GAAK,IACxB2W,WAAa,sQavGLC,wCAEnBnU,OAAAA,aAAS,WACToU,OAAAA,iDAEKpU,OAASA,OACToU,OAASA,OACTC,UAAY,QACZC,WAAa,QACbC,mBACAC,gBAAkB,OAElBtT,EAAI,OACJhG,EAAI,OAEJnF,IAAM,OACNI,KAAO,OAEPse,oEAIAC,qDAIAtb,YACAub,qEAIA1J,UAAY1V,EAAEwV,OAAO,cACjB6J,KAAK5U,iBACF,8JAKP6U,eAEAC,MAAQF,KAAK3J,UAAUvV,cAAc,eACrCqf,cAAgBH,KAAK3J,UAAUvV,cAAc,yBAE7CsK,OAAOgV,iBAAiB,aAAc,aACrCH,sDAKFC,QACDF,MAAKrQ,YACF0G,UAAU1L,aAAa,mBAAoBqV,KAAKrQ,SAEnDqQ,KAAKJ,2BACYI,KAAKN,uBAAsBM,KAAKP,UAExCO,KAAKP,qBAAoBO,KAAKN,4BAErCQ,MAAM5J,UAAY4J,OAClBC,cAAc7J,UAAY,QAE1BqJ,WAAWlV,IAAI,SAAC4V,EAAKzY,MACnB0B,GAAQgX,EAAKd,OAAO5X,IAAM,QAC5B/B,EAA0B,IAAlBwa,EAAIE,WAAmBF,EAAIE,UAAYF,EAAIE,UAAYF,EAAIxa,MAEnE2a,EAAK7f,EAAEwV,OAAO,wCAEW7M,iDAE6B,IAAVzD,GAAeA,EAAQA,EAAQ,6BAC3Ewa,EAAIH,MAAQG,EAAIH,MAAQ,QAGvBC,cAAc5f,YAAYigB,+CAK5BlV,GAAQ0U,KAAK3J,UAAUoK,iBAEtBtf,IAAM6e,KAAK1Z,EAAI0Z,KAAK3J,UAAUqK,aAChCxB,qCACE3d,KAAOye,KAAK1T,EAAIhB,EAAM,KACvBqV,GAAUX,KAAK5U,OAAOqV,YAAcnV,EAEpCsV,EAAUZ,KAAK3J,UAAUvV,cAAc,mBAExCkf,KAAKze,KAAO,IACNrB,MAAMqB,oBAAsB,EAAIye,KAAKze,gBACxCA,KAAO,MACN,IAAGye,KAAKze,KAAOof,EAAS,IAE1BE,kBADQb,KAAKze,KAAOof,WAEhBzgB,MAAMqB,KAAOsf,OAEhBtf,KAAOof,SAEJzgB,MAAMqB,6CAIN+K,EAAGhG,MAAG4Z,6DAAYP,4DAAiBhQ,0DAAS,OAChD8P,UAAYS,EAAMrH,UAClB6G,WAAaQ,EAAMra,WACnB8Z,WAAaA,OACbrT,EAAIA,OACJhG,EAAIA,OACJsZ,gBAAkBM,EAAMY,YAAc,OACtCnR,MAAQA,OACRoR,iDAIA1K,UAAUnW,MAAMiB,IAAM,WACtBkV,UAAUnW,MAAMqB,KAAO,WACvB8U,UAAUnW,MAAMgL,QAAU,2CAI1BmL,UAAUnW,MAAMiB,IAAM6e,KAAK7e,IAAM,UACjCkV,UAAUnW,MAAMqB,KAAOye,KAAKze,KAAO,UACnC8U,UAAUnW,MAAMgL,QAAU,iOV5H3B8V,+BACS,eACN,iBACE,cACH,iBACG,iBACA,gBACD,wBACM,iBACL,kBACC,gBACF,eACD,uBACM,sBACD,WA8BDvX,SAAW,SAACH,SAEpB,4BAA6BY,KAAKZ,iCACE2X,KAAK3X,GAC1CmB,IAAI,SAAC6B,EAAG1E,SAAa,KAANA,EAAUtC,OAAOgH,GAAGvC,SAAS,IAAM,MAClDlB,OAAO,SAACqY,EAAGC,YAAUD,EAAIC,IAErBH,iBAAiB1X,IAAUA,0oBC9CtB6F,iBAAmB,EAC1BT,aAAe,EACfjB,gBAAkB,GACXE,UAAY,GACnBc,gBAAkB,UAClBb,UAAY,UAkmBPwT,iBACH,SAACxQ,MACHyQ,SACiB,UAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBuP,GAAU1Q,EAAK+C,qBACXzT,MAAMsE,KAAO,YACbtE,MAAMgL,QAAU,MAErBmW,KACM1W,aAAa,YAAa0W,GAE5BC,OAGD,SAAC1Q,MACHyQ,SACiB,YAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBuP,GAAU1Q,EAAK+C,YACf5O,EAAS6L,EAAKqB,aAAa,KAC3BzN,EAAOoM,EAAKqB,aAAa,iBACrBtH,aAAa,IAAKf,SAAS7E,GAAU8Z,yBACrClU,aAAa,OAAQnG,KACrBtE,MAAMgL,QAAU,MAErBmW,KACM1W,aAAa,YAAa0W,GAE5BC,eAGO,SAAC1Q,MACXyQ,SACiB,YAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBuP,GAAU1Q,EAAK+C,YACf5O,EAAS6L,EAAKqB,aAAa,KAC3BzN,EAAOoM,EAAKqB,aAAa,iBACrBtH,aAAa,IAAKf,SAAS7E,GAAU8Z,yBACrClU,aAAa,OAAQnG,KACrBtE,MAAMgL,QAAU,MAErBmW,KACM1W,aAAa,YAAa0W,GAE5BC,IAIEC,mBACH,SAAC3Q,EAAM0Q,MACTD,SACiB,UAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpByP,IAAc,IAAK,IAAK,QAAS,iBAC9B5G,OAAOhK,EAAK4Q,YACjBtI,OAAO,kBAAQsI,GAAWrI,SAASsI,EAAK5I,OAAS4I,EAAKC,YACtDjX,IAAI,cACIE,aAAa8W,EAAK5I,KAAM4I,EAAKE,aAGpCN,KACM1W,aAAa,YAAa0W,QAI7B,SAACzQ,EAAM0Q,MACTD,SACiB,YAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpByP,IAAc,KAAM,aACjB5G,OAAOhK,EAAK4Q,YACjBtI,OAAO,kBAAQsI,GAAWrI,SAASsI,EAAK5I,OAAS4I,EAAKC,YACtDjX,IAAI,cACIE,aAAa8W,EAAK5I,KAAM4I,EAAKE,aAGpCN,KACM1W,aAAa,YAAa0W,gBAIrB,SAACzQ,EAAM0Q,MACjBD,SACiB,YAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpByP,IAAc,KAAM,aACjB5G,OAAOhK,EAAK4Q,YACjBtI,OAAO,kBAAQsI,GAAWrI,SAASsI,EAAK5I,OAAS4I,EAAKC,YACtDjX,IAAI,cACIE,aAAa8W,EAAK5I,KAAM4I,EAAKE,aAGpCN,KACM1W,aAAa,YAAa0W,0bCrtBxBhP,cAAgB,IAChBU,cAAgB,IAChB1B,qBAAuBgB,cACvB4C,oBAAsB,IAEtBhE,WAAa,8bCHpBgD,aACC,yBACE,iBAEA,wBACC,uBACE,iBQVCmC,QAAU,48DCUFwL,gCACRxW,EAAQ6C,kCAETtI,UAAUsI,QAEf7C,OAA2B,gBAAXA,GAClBrL,SAASe,cAAcsK,GACvBA,IAEG4U,KAAK5U,iBAAkByW,mBACtB,IAAIC,OAAM,uDAGZC,aAAe9T,OAEfiS,MAAQjS,EAAQiS,OAAS,QACzB9f,KAAO6N,EAAQ7N,MAAQ,QAEvBkd,SAAW0C,KAAKgC,YAAY/T,EAAQV,WACpCA,KAAOyS,KAAKiC,iBAAiBjC,KAAK1C,eAElCkC,OAASQ,KAAKkC,eAAejU,EAAQuR,OAAQQ,KAAK5f,WAElDiZ,oBACS,aACD,cACCpL,EAAQkU,aAAe,cACC,KAApBlU,EAAQmU,QAA2BnU,EAAQmU,QAAU,kBACrDnU,EAAQoU,iBAAmB,QAGxCC,SAAWC,KAAKC,MAAMD,KAAKE,UAAUpE,mBACtCjb,GAAI4c,KAAKsC,cACRI,YAAYzU,GACb+R,KAAKE,MAAM/b,WAAYd,YAAc,GACrC2c,KAAK3G,OAAOsJ,aAAYvf,EAAEM,aAAe,QACxCkf,UAAY3U,EAAQ5H,QAAUjD,EAAEyf,gBAEhCC,cACA7U,gBAEA8U,YAAczE,0BAEhB0B,KAAK3G,OAAO8I,mBACTa,kBAGDC,UAAUhV,8DAGJV,SACJA,4CAGSA,SACTA,0CAGOiS,EAAQpf,MAChB8iB,gBACI1D,OAAc/a,OAAO4a,eAAejf,KACvC+iB,QAAQ,SAACxe,MACT2E,GAAQG,SAAS9E,EACnBqF,cAAaV,KAGJzB,KAAKyB,WAFT8Z,KAAK,IAAMze,EAAS,6BAKvBue,wFASH7c,EAAS2Z,KAAK4C,eACbC,WAAaxc,OACbA,OAASA,EAAS5C,eAAeuc,KAAKsC,eAGtCe,YAAc,iBAAMC,GAAKC,MAAK,IAC/BC,sBACEC,eAAiB,GAAID,gBAAexD,KAAKqD,kBACzCI,eAAeC,QAAQ1D,KAAK5U,gBAE3BgV,iBAAiB,SAAUJ,KAAKqD,oBAChCjD,iBAAiB,oBAAqBJ,KAAKqD,+CAI9CrD,KAAKyD,gBAAgBzD,KAAKyD,eAAeE,oBACtCC,oBAAoB,SAAU5D,KAAKqD,oBACnCO,oBAAoB,oBAAqB5D,KAAKqD,kDAKhDQ,qBACAC,mBACAhE,mBAEAyD,MAAK,GAAO,gDAKZnY,OAAOkL,UAAY,MAEpB3K,WACKqU,KAAK5U,iBACF,kBAGT4U,MAAK+D,qBACF1hB,QAAWiJ,MAAO0U,KAAK+D,iBAAmB,YAG3C1N,UAAY1V,EAAEwV,OAAO,MAAOxK,8CAI5BqY,IAAM,GAAIzE,gBACNS,KAAK3J,iBACL2J,KAAKR,cAETyE,+FAKDC,0DAAuBC,yDACvBD,IAAmBziB,SAASue,KAAK5U,eAIhC0Y,mBAEAM,KAAKF,QACLG,qBACAC,uBAEAC,WAAWpB,QAAQ,kBAAKjC,GAAErB,MAAMS,EAAKkE,iBAErCC,OAAOzE,KAAKuE,YAAY,GAE1BJ,SACG5W,KAAOyS,KAAK1C,oBACN,aAAYoH,OAAOpE,EAAK/S,OAASyS,KAAK+C,mBAG7C4B,oBAEAC,gBAAgBT,+EAMhBU,UAAYziB,uBAAuB4d,KAAK5U,aACxCE,MAAQ0U,KAAK6E,UAAYlhB,cAAcqc,KAAKsC,kDAI9CtC,KAAKlK,UACFO,UAAUrB,YAAYgL,KAAKlK,QAE7B1S,GAAI4c,KAAKsC,cAERxM,IAAM3K,iBACV6U,KAAK3J,UACL,qBACA2J,KAAK6E,UACL7E,KAAK6C,iBAEDtS,QAAUhF,YAAYyU,KAAKlK,KAE7BkK,KAAKE,MAAM/b,cACR2gB,QAAU/W,SACd,QACA3K,EAAEE,QAAQ/B,KACV6B,EAAEE,QAAQnC,IACV6e,KAAKE,gBAEM9c,EAAE2hB,mBACN,aACF3hB,EAAE2hB,oBAKL5jB,GAAMgC,aAAaC,QAClBohB,SAAW/Y,aACfuU,KAAK5f,KAAO,sCACCoD,cAAcJ,QAAOjC,OAGhC6e,KAAK3G,OAAOsJ,gBACP3C,KAAK3Z,OAASjD,EAAEG,SAAS1B,YAC3BmjB,WAAavZ,aACjB,4BACajI,cAAcJ,QAAOjC,QAIjC6e,KAAKE,MAAM/b,aAAe2R,IAAIvV,YAAYyf,KAAK8E,cAC7ChP,IAAIvV,YAAYyf,KAAKwE,UACvBxE,KAAK3G,OAAOsJ,iBAAmB7M,IAAIvV,YAAYyf,KAAKgF,iBAElDC,gBAAgBzhB,cAAcJ,GAAID,aAAaC,4CAGrCkJ,EAAGhG,QACb0d,IAAI/Y,UACLqB,IACAhG,kDAIoBie,WAAa,GAAIW,oCAEnC3X,GACFA,WACK6Q,MAAM,2BAEV7Q,KAAOyS,KAAKgC,YAAYzU,QACxB6W,YACAK,OAAOzE,KAAKuE,WAAYvE,KAAK3G,OAAO+I,cACpCuC,2DAGCJ,yDAAWvE,KAAKuE,WAAYnC,4DAC/BpC,MAAK3G,OAAO8I,kBAETa,SAASvY,IAAI,kBAAK/B,GAAE6B,WAAWyK,YAAYtM,QAG7CoM,QAEOqO,QAAQ,cACErO,EAAkBrQ,OAAOyc,EAAEwD,OAAOtC,MAEpDtN,EAAkB3Q,OAAS,oBACZ6b,KAAK3J,UAAW2J,KAAKlK,IAAKhB,cAChC,aACCqO,QAAQ,kBAAKjC,GAAEiE,WACrBC,aACH7G,gCAEQ4E,QAAQ,kBAAKjC,GAAEiE,cACrBC,iDAKHpF,KAAK3G,OAAO8I,mBACTf,mBACAiE,0GAMSlB,yDACXnE,MAAK3G,OAAO8I,aAEbgC,SACGmB,mBAEAC,eACEvF,KAAKwF,WAAWC,KAAKzF,SACrBA,KAAK0F,YAAYD,KAAKzF,SACtBA,KAAK2F,UAAUF,KAAKzF,SACpBA,KAAK4F,aAAaH,KAAKzF,SACvBA,KAAK6F,YAAYJ,KAAKzF,gBAGpBI,iBAAiB,UAAW,SAAC0F,GAClClkB,oBAAoBmkB,EAAK1P,eACvByP,GAAKhkB,OAAOkkB,MACbD,EAAKR,WAAWO,EAAEG,YACfV,WAAWO,EAAEG,mmBA2BlBC,GAAWrQ,iBAAiBmK,KAAKlK,kBACxBkK,KAAKE,OAAS,SAAUgG,4gBC3TlBC,wCACR/a,EAAQO,wHACbP,EAAQO,8EAGLA,gGACOA,QAEX0N,OAAO+M,gBAAkBza,EAAK0a,oBAAsBD,oBACpD/M,OAAOiN,UAAY3a,EAAK2a,WAAa,QACrCjN,OAAOkN,gBAAkB5a,EAAK4a,iBAAmB,6CAIlDC,EAAIxG,KAAK8C,MACTwD,EAAYtG,KAAK3G,OAAOiN,YAC1BG,kBAEEC,GAAY1G,KAAKzS,KAAKqP,OAAOnS,IAAI,SAACzD,EAAOY,MACxC+e,GAAQ,WACPpZ,KAAKuP,SAASrS,IAAI,eACbqb,EAAElL,OAAOhT,MAEX+e,EAAO3f,KACbkS,OAAO,kBAAcrV,GAAE,IAAM,IAE5B+iB,EAASF,KACVA,EAAUviB,OAASmiB,EAAW,GAEtBO,KAAK,SAAC7d,EAAGa,SAAeA,GAAE,GAAKb,EAAE,OAElC0d,EAAU5f,MAAM,EAAGwf,EAAU,MAGlCQ,GAAiB,CAFLJ,GAAU5f,MAAMwf,EAAU,GAGhC7b,IAAI,eAAwB5G,EAAE,OACjCgE,MAAMif,EAAgB,cACxBtH,OAAO8G,EAAU,GAAK,SAG1B1J,YACKnS,IAAI,cACRgc,YAAY5e,KAAKnC,MAAM7B,EAAE,OACzB+Y,OAAO/U,KAAKhE,EAAE,QAGfkjB,WAAaP,EAAEC,YAAY5d,OAAO,SAACG,EAAGa,SAAMb,GAAIa,GAAG,QAEhDqC,UACD8T,KAAK1U,MAAQ,IACb0U,KAAK3Z,OAAS,qDAKdmgB,EAAIxG,KAAK8C,WACRkC,WAAWgC,YAAc,QACzBC,aAAeT,EAAEC,YAAY3f,MAAM,EAAGkZ,KAAK3G,OAAOkN,oBAEnDtiB,GAAQ,EACRqC,EAAI,OACH2gB,aAAaxc,IAAI,SAAC5G,EAAG+D,MACrBsf,GAAW,IACXC,EAAU7iB,KAAK6C,OACjBigB,EAAK9b,MAAQ3H,cAAcyjB,EAAK9E,WAAW4E,EAEzCE,GAAKH,aAAa9iB,OAASgjB,MACnBC,EAAK9b,MAAM8b,EAAKH,aAAa9iB,QAEtCF,EAAQkjB,MACF,KACH,OAEF7a,GAAI4a,EAAWjjB,EAAQ,EACvB+C,EAAQogB,EAAK/N,OAAOgJ,gBAAkB1b,eAAe6f,EAAE5J,OAAOhV,GAAIsf,EAAS,IAAMV,EAAE5J,OAAOhV,GAC1F2Y,EAAY6G,EAAK/N,OAAO+M,eAAiBgB,EAAK/N,OAAO+M,eAAeviB,GAAKA,EACzEkM,EAAMjC,UACTxB,EACAhG,EACA,EACA8gB,EAAK5H,OAAO5X,GACTZ,OAAUuZ,GACb,KAEIyE,WAAWzkB,YAAYwP,gBApFe6R,WRJjCyF,kBAAoB,GACpB3P,mBAAqB,EAErBG,aAAe,IACfD,WAAa,MAEbM,aAAe,UAAW,WAAY,QAAS,QAAS,MACpE,OAAQ,OAAQ,SAAU,YAAa,UAAW,WAAY,YAIlDoP,iBAAmB,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,8rBCNpE/N,gDAEJgO,WAAAA,aAAa,SACbC,eAAAA,aAAiB,KACjB1O,IAAAA,UAEAC,IAAAA,QACA0O,IAAAA,aACAC,IAAAA,+CAEKF,eAAiBA,OACjB1O,UAAYA,OAEZ2O,aAAeA,OACf1O,QAAUA,OAEV2O,gBAAkBA,OAElBC,cACA/K,eAEA2K,WAAaA,OACbA,WAAyC,kBAArBvH,MAAKuH,WAC3BvH,KAAKuH,aAAevH,KAAKuH,gBAEvBxG,iEAGExT,QACFA,KAAOA,GAAQyS,KAAKjH,wCAGpB3N,QACAwc,MAAQnc,aAAauU,KAAKuH,WAAYvH,KAAKwH,eAAgBpc,uCAI3DqZ,OAAOzE,KAAKzS,WACZsa,QAAU7H,KAAKzS,oCAGdA,mBACDoa,MAAQ3H,KAAKyH,aAAala,QAE1Bqa,MAAMZ,YAAc,QACpBW,MAAMxE,QAAQ,cACbyE,MAAMrnB,YAAYS,UAEnB4b,OAAOuG,QAAQ,cACdyE,MAAMrnB,YAAYS,yCAIlBohB,mEACDrB,aACD2G,YACDtF,OACgBpC,KAAK0H,gBAAgB1H,KAAKzS,WAEtCma,WAILzO,0CAEU,qCACC1L,SACLA,GAAKua,aAAard,IAAI,SAAC+b,EAAG5e,MAC5Bd,GAAQ+E,SAAS2a,EAAG,aAAcjZ,EAAKiS,OAAO5X,GAAI,OAAQ2F,EAAKwa,sBAC7D7nB,MAAM8nB,WAAa,iBAClBlhB,8BAIOmhB,SACRjI,MAAK2H,MAAMld,IAAI,SAAC3D,EAAOc,SAAMuL,gBAAerM,EAAOmhB,EAAQH,aAAalgB,8BAIpE,mCACC2F,SACLA,GAAKua,aAAard,IAAI,SAAC+b,EAAG5e,MAC5Bd,GAAQ+E,SAAS2a,EAAG,WAAY,OAAQjZ,EAAKiS,OAAO5X,aAClD1H,MAAM8nB,WAAa,iBAClBlhB,8BAIOmhB,SACRjI,MAAK2H,MAAMld,IAAI,SAAC3D,EAAOc,SAC7BuL,gBAAerM,EAAOmhB,EAAQH,aAAalgB,mCAKjC,wCACC2F,oBACLA,GAAK2a,WAAWzd,IAAI,SAAC6B,EAAG1E,SAEpBsF,eAAcZ,EADhB,EACsBiB,EAAK4a,OAAOvgB,GACzC0Y,EAAKxH,UAAUsP,UAAW9H,EAAKxH,UAAUuP,SAAU9a,EAAKiS,OAAO5X,gCAKlDqgB,MACZA,EAAS,6BAID,+BACC1a,oBACLA,GAAK+a,UAAU7d,IAAI,SAAC8d,EAAU3gB,SACpCoH,OAAMuZ,EAAUhb,EAAKqP,OAAOhV,GAAIwf,EAAKtO,UAAUxN,OAC7C4D,KAAMkY,EAAKtO,UAAU5J,KAAMD,IAAKmY,EAAKtO,UAAU7J,IAAKF,eAAgBqY,EAAKtO,UAAU/J,6CAIvEkZ,MACXO,GAASP,EAAQK,UACjBG,EAAYR,EAAQrL,OACpB8L,EAAS1I,KAAK6H,QAAQS,UACtBK,EAAY3I,KAAK6H,QAAQjL,SAEVrW,qBAAqBmiB,EAAQF,+CACvBjiB,qBAAqBoiB,EAAWF,qDAEpDhE,kBACOiE,SACHD,IAGFzI,KAAK2H,MAAMld,IAAI,SAAC3C,EAAMF,SACrB0J,mBACNxJ,EAAM0gB,EAAO5gB,GAAI8gB,EAAO9gB,0BAOf,+BACC2F,oBACLA,GAAK+a,UAAU7d,IAAI,SAAC8d,EAAU3gB,SACpCwH,OAAMmZ,EAAUhb,EAAKqb,WAAWhhB,GAAIme,EAAKjN,UAAUzS,QACjD6I,KAAM6W,EAAKjN,UAAU5J,KAAMD,IAAK8W,EAAKjN,UAAU7J,kCAInCgZ,MACXO,GAASP,EAAQK,UACjBG,EAAYR,EAAQW,WACpBF,EAAS1I,KAAK6H,QAAQS,UACtBK,EAAY3I,KAAK6H,QAAQe,aAEVriB,qBAAqBmiB,EAAQF,+CACvBjiB,qBAAqBoiB,EAAWF,qDAEpDhE,kBACOiE,aACCD,IAGNzI,KAAK2H,MAAMld,IAAI,SAAC3C,EAAMF,SACrBsJ,mBACNpJ,EAAM0gB,EAAO5gB,GAAI8gB,EAAO9gB,6BAOf,kCACC2F,oBACLA,GAAK9C,IAAI,kBACf4E,SAAQjM,EAAEmlB,SAAUnlB,EAAE4D,MAAO6hB,EAAK/P,UAAUxN,OAC1CgE,SAAUlM,EAAE6K,QAAQqB,SAAUJ,KAAM,OAAQJ,SAAU,uCAG1CmZ,SACW1hB,qBAAqByZ,KAAK6H,QAASI,gCAAvDJ,gBAEFW,YAAiB/d,IAAI,kBAAK5G,GAAE0kB,WAC5BE,EAAYR,EAAQxd,IAAI,kBAAK5G,GAAEmD,QAC/B8hB,EAAab,EAAQxd,IAAI,kBAAK5G,GAAEoK,UAEhCya,EAAS1I,KAAK6H,QAAQpd,IAAI,kBAAK5G,GAAE0kB,uBAEhC9D,OAAOiE,EAAOje,IAAI,SAACwE,EAAKrH,mBAEjB8gB,EAAO9gB,SACV6gB,EAAU7gB,WACRkhB,EAAWlhB,OAIfoY,KAAK2H,MAAMld,IAAI,SAAC3C,EAAMF,SACrB0J,mBACNxJ,EAAM0gB,EAAO5gB,GAAI8gB,EAAO9gB,6BAOf,kCACC2F,oBACLA,GAAK9C,IAAI,kBACf+E,SAAQpG,EAAE2f,SAAU3f,EAAE4f,OAAQC,EAAKnQ,UAAUxN,MAC5ClC,EAAEpC,OAAQsI,SAAUlG,EAAE6E,QAAQqB,uCAGjB2Y,SACW1hB,qBAAqByZ,KAAK6H,QAASI,gCAAvDJ,gBAEFW,YAAiB/d,IAAI,kBAAK5G,GAAEmlB,SAC5BP,EAAYR,EAAQxd,IAAI,kBAAK5G,GAAEmD,QAC/BkiB,EAAYjB,EAAQxd,IAAI,kBAAK5G,GAAEklB,WAC/BD,EAAab,EAAQxd,IAAI,kBAAK5G,GAAEoK,UAEhCya,EAAS1I,KAAK6H,QAAQpd,IAAI,kBAAK5G,GAAEmlB,SACjCG,EAAYnJ,KAAK6H,QAAQpd,IAAI,kBAAK5G,GAAEklB,gBAEnCtE,OAAOiE,EAAOje,IAAI,SAACwE,EAAKrH,mBAEjBuhB,EAAUvhB,UACZ8gB,EAAO9gB,SACR6gB,EAAU7gB,WACRkhB,EAAWlhB,UAIlB8f,kBAECC,MAAMld,IAAI,SAACiH,EAAW9J,KACR8f,EAAgBjjB,OAAOgN,cACxCC,EAAWwX,EAAUthB,GAAI4gB,EAAO5gB,GAAI8gB,EAAO9gB,OAItC8f,2BAKI,iBAAoB,sBAAwB1H,KAAKlH,UAAUnJ,6BAC1DpC,gBACuDyS,KAAKlH,UAAnEnJ,IAAAA,MAAOyZ,IAAAA,SAAUC,IAAAA,UAAWC,IAAAA,WAAYvkB,IAAAA,OAEzCuH,IAFiDid,WAEjCjjB,EAAI,cAEnBkjB,0BAEAC,KAAKhf,IAAI,SAACif,EAAMC,GACN,IAAXA,KACG/M,OAAO/U,KACXkG,SAAS,cAAezB,GARL,GAQyByL,aAAapI,GAAO,GAAMia,wBAE1D,OAKTnf,IAAI,SAAC8N,EAAK3Q,MACX2Q,EAAI/T,KAAM,IACR+I,gBACUgL,EAAIsR,sBACHtR,EAAIuR,qBACNliB,GAETmiB,EAAS1c,WAAW,MAAOf,EAAGhG,EAAGgjB,EAAYvkB,EAAQwT,EAAI/T,KAAM+I,KAC9Dic,qBAAqB3hB,KAAKkiB,MAE3BV,MAEF,KACCD,IAGCpJ,KAAKwJ,+CAGGvB,MACZA,EAAS,gCAKD,iBAAoB,sCAAwCjI,KAAKlH,UAAUnJ,6BAC1EpC,MACR2T,GAAIlB,KAAKlH,sBACRkR,SAAW,WACXC,MAAQ1c,EAAK2c,WAAWzf,IAAI,SAACnE,EAAGrD,SAC7ByM,YACNnC,EAAK2a,WAAWjlB,GAChBqD,EACAiH,EAAK2Z,SACLhG,EAAE5X,MACFiE,EAAKqP,OAAO3Z,GACZA,EACAsK,EAAK4c,QAAQlnB,aAEFsK,EAAKnH,mBACJmH,EAAK6c,oBACLlJ,EAAErR,cAITmQ,KAAKiK,gCAEGhC,MACXoC,GAAUpC,EAAQC,WAClBoC,EAAUrC,EAAQiC,WAClBK,EAAatC,EAAQkC,QACrB1B,EAAYR,EAAQrL,OAEpB4N,EAAUxK,KAAK6H,QAAQK,WACvBuC,EAAUzK,KAAK6H,QAAQqC,WACvBQ,EAAa1K,KAAK6H,QAAQsC,QAC1BxB,EAAY3I,KAAK6H,QAAQjL,SAERrW,qBAAqBikB,EAASH,+CAC9B9jB,qBAAqBkkB,EAASH,+CACxB/jB,qBAAqBmkB,EAAYH,+CACnChkB,qBAAqBoiB,EAAWF,8CAEpDhE,mBACQ+F,aACAC,UACHC,SACDjC,WAEEzI,KAAK6H,QAAQzhB,mBACZ4Z,KAAK6H,QAAQuC,mBACdpK,KAAK6H,QAAQX,cAGpBQ,kBAECC,MAAMld,IAAI,SAAC0H,EAAKvK,KACF8f,EAAgBjjB,OAAOyN,WACxCC,EAAKkY,EAAQziB,GAAI0iB,EAAQ1iB,GAAIqgB,EAAQf,SAAUqD,EAAW3iB,IACzDxB,SAAU6hB,EAAQ7hB,cAIdshB,0BAKI,iBAAoB,sCAAwC1H,KAAKlH,UAAUnJ,6BAC1EpC,MACR2T,GAAIlB,KAAKlH,sBACRkR,SAAW,WACXxZ,SACD0Q,EAAEyJ,gBACAna,MAAQR,SACZzC,EAAK2a,WACL3a,EAAK2c,WACLhJ,EAAE5X,gBAES4X,EAAE7Q,oBACA6Q,EAAEzQ,kBACNyQ,EAAE/Q,iBAGD+Q,EAAE3Q,iBACDhD,EAAKnH,iBAKb6jB,SACD/I,EAAE0J,gBACAX,MAAQ1c,EAAK2c,WAAWzf,IAAI,SAACnE,EAAGrD,SAC7B6M,YACNvC,EAAK2a,WAAWjlB,GAChBqD,EACAiH,EAAKxI,OACLmc,EAAE5X,MACD4X,EAAE2J,iBAAmBtd,EAAKqN,OAAO3X,GAAK,GACvCA,MAKI+V,OAAO4B,OAAOoF,KAAKxP,OAAO/L,OAAOub,KAAKiK,iCAE9BhC,MACXoC,GAAUpC,EAAQC,WAClBoC,EAAUrC,EAAQiC,WAClBY,EAAY7C,EAAQrN,OAEpB4P,EAAUxK,KAAK6H,QAAQK,WACvBuC,EAAUzK,KAAK6H,QAAQqC,WACvBzW,EAAYuM,KAAK6H,QAAQjN,SAERrU,qBAAqBikB,EAASH,+CAC9B9jB,qBAAqBkkB,EAASH,+CAC1B/jB,qBAAqBkN,EAAWqX,8CAEpDrG,mBACQ+F,aACAC,SACJK,WAEE9K,KAAK6H,QAAQzhB,gBACf4Z,KAAK6H,QAAQ9iB,YAGlB2iB,YAED1O,QAAOxO,KAAKwV,KAAKxP,OAAOrM,WACRujB,EAAgBjjB,OAAOiO,YACxCsN,KAAKxP,MAAO6Z,EAASC,EAASrC,EAAQ7hB,SAAU4Z,KAAKlH,UAAU3I,UAG9D6P,KAAKiK,MAAM9lB,aACR8lB,MAAMxf,IAAI,SAACsF,EAAKnI,KACF8f,EAAgBjjB,OAAO8N,WACxCxC,EAAKsa,EAAQziB,GAAI0iB,EAAQ1iB,OAIrB8f,ggBQ3aWqD,uCACR3f,EAAQO,qHACbP,EAAQO,aACTvL,KAAO,eACPyf,kFAGM5R,MACP7K,GAAI4c,KAAKsC,cACR0I,WAAa/c,EAAQ+c,kBAEtBnhB,GAAImW,KAAKgL,aACX3kB,OAASwD,EAAExD,QAAUyY,gCACrB3R,MAAQtD,EAAEsD,OAASC,+BAEnB7J,SAAStB,MAAQ,KACjByB,aAAe,KACfmf,WAA0C,GAA5BhZ,EAAExD,OAAmB,GAAVwD,EAAEsD,oDAIzBqZ,GAAIxG,KAAK8C,MAET7J,IAEF,4BAEY+G,KAAKgL,WAAW3kB,gBACjB2Z,KAAKgL,WAAW7d,OAE3B,6BAEcqZ,EAAE0B,kBACN1B,EAAE2B,cACFnI,KAAKR,SAEbiG,KAAKzF,aAIJuE,WAAa,GAAIW,KAAIjM,EACxBxO,IAAI,eACAwgB,GAAYrS,6CAAgBjN,WACxBA,EAAK,GAAIsf,0IAMfzE,GAAIxG,KAAK8C,QAEXoF,gBACAC,aAEE+C,GAAO,IACTzE,YAAYhc,IAAI,SAAC5E,MACdyF,GAAQgV,EAAKhV,MAAQzF,EAAQ2gB,EAAEO,aACjCoB,OAAOtgB,KAAKyD,KACZ4c,WAAWrgB,KAAKqjB,MACV5f,gGAOLkb,EAAIxG,KAAK8C,WACRzM,UAAU+J,iBAAiB,YAAa,SAAC0F,MACzCqF,GAAO/D,EAAK7C,WAAW6G,IAAI,kBAAkBzD,MAC7CxV,EAAM2T,EAAEljB,UACTuoB,EAAKhS,SAAShH,GAAM,IAElBvK,GAAIujB,EAAK3P,QAAQrJ,GACjBkZ,EAAOtqB,UAAUqmB,EAAK/Q,WAAYiV,EAAOvqB,UAAUoR,GAEnD7F,EAAIgf,EAAK/pB,KAAO8pB,EAAK9pB,KAAOqI,SAASuI,EAAIF,aAAa,UAAU,EAChE3L,EAAIglB,EAAKnqB,IAAMkqB,EAAKlqB,IACpB+e,GAASkH,EAAKmE,iBAAmBnE,EAAKmE,gBAAgBpnB,OAAO,EAC9DijB,EAAKmE,gBAAgB3jB,GAAKwf,EAAKtE,MAAMlG,OAAOhV,IAAM,KACjD4jB,EAAWhF,EAAEC,YAAY7e,GAAG4e,EAAEO,aAE7B/C,IAAIyH,UAAUnf,EAAGhG,GAAIuS,KAAMqH,EAAOra,OAAiB,IAAT2lB,GAAc1nB,QAAQ,GAAK,QACrEkgB,IAAI0H,oBAlFgCvF,ihBCIxBwF,gCACRvgB,EAAQO,uHACbP,EAAQO,aACTvL,KAAO,QACP2iB,YAAc,IACdoB,KAAO,IAEPtE,oFAGIlU,gGACOA,QACXigB,UAAY5L,KAAK4L,UAAUnG,KAAKzF,WAChC6L,WAAa7L,KAAK6L,WAAWpG,KAAKzF,WAElC8L,WAAangB,EAAKmgB,YAAc,QAChCzS,OAAO0S,WAAapgB,EAAKogB,YAAc,OAEvC5f,UAAYR,EAAKQ,YAAa,wIAK/Bqa,GAAIxG,KAAK8C,WACR/d,OAAUib,KAAK3Z,OAAS2Z,KAAK1U,MAAQ0U,KAAK9T,OAAOI,EAAI0T,KAAK9T,OAAO5F,KAE9DvB,GAAsBib,KAAtBjb,OAAQoH,EAAc6T,KAAd7T,UAEV6f,EAAuBxF,EAAEyF,uBAC7BnE,kBACAmE,uBACEC,GAAW,IAAMlM,KAAK3G,OAAO0S,aAC/BtF,YAAYhc,IAAI,SAACkc,EAAO/e,MACnBmkB,GAAaG,EACbC,EAAmBxF,EAAQH,EAAEO,WAAczH,WAC3ClT,EAAW+f,EAAkB,IAAM,EAAG,EACtCC,EAAYjgB,GAAaggB,EAAkBA,EAC3CE,EAAWH,GAAsBE,EACjCpgB,EAAgBnH,mBAAmBknB,EAAYhnB,GAC/CkH,EAAcpH,mBAAmBwnB,EAAUtnB,GAE3CunB,EAAehM,EAAK6D,MAAQ6H,EAAqBpkB,GAEnD2kB,SAASC,QACVlM,GAAK6D,QACImI,EAAeA,EAAatgB,cAAgBA,IAC9CsgB,EAAeA,EAAargB,YAAcD,MAExCA,IACFC,MAEJwgB,GACe,MAApBN,EACGzf,cAAc6f,EAAUC,EAAQlM,EAAKpU,OAAQoU,EAAKvb,OAAQoH,EAAWC,GACrEL,eAAewgB,EAAUC,EAAQlM,EAAKpU,OAAQoU,EAAKvb,OAAQoH,EAAWC,KAExE0b,aAAajgB,KAAK4kB,KAClBR,iBAAiBpkB,0CAGX8e,QACAH,EAAEO,yCAGFqF,WAIJjI,KAAO,+CAIRqC,GAAIxG,KAAK8C,MAET7J,IAEF,eAEA,+BAEgBuN,EAAEsB,oBACR9H,KAAKR,SAEbiG,KAAKzF,aAIJuE,WAAa,GAAIW,KAAIjM,EACxBxO,IAAI,eACAwgB,GAAYrS,+CAAgBjN,WACxBA,EAAK,GAAIsf,kDAIAyB,MACb3nB,GAAqBib,KAArBjb,OAAO+mB,EAAc9L,KAAd8L,WACPvD,EAAW1jB,mBAAmB6nB,EAASX,WAAYW,EAAS5nB,MAAQ,EAAGC,wBACtDwjB,EAASjc,EAAKwf,QAAiBvD,EAASjiB,EAAKwlB,6CAG1D1b,EAAKxI,EAAE+kB,EAAK7G,MAClB1V,MACE9G,GAAQ0W,KAAKR,OAAO5X,MACvB+kB,EAAM,WACEvc,EAAM4P,KAAK4M,oBAAoB5M,KAAK8C,MAAMmJ,iBAAiBrkB,OAChE1H,MAAMsE,KAAO6E,mBAAmBC,EAAO,OACxCujB,GAAQ9rB,UAAUif,KAAKlK,KACvBxJ,EAAIwZ,EAAEgH,MAAQD,EAAMtrB,KAAO,GAC3B+E,EAAIwf,EAAEiH,MAAQF,EAAM1rB,IAAM,GAC1B+e,GAASF,KAAKgN,kBAAoBhN,KAAKgN,iBAAiB7oB,OAAS,EAClE6b,KAAKgN,iBAAiBplB,GAAKoY,KAAK8C,MAAMlG,OAAOhV,IAAM,KAClDqlB,GAAuC,IAA5BjN,KAAK8C,MAAM2D,YAAY7e,GAAWoY,KAAK8C,MAAMiE,YAAYjjB,QAAQ,QAC3EkgB,IAAIyH,UAAUnf,EAAGhG,GAAIuS,KAAMqH,EAAOra,MAAOonB,EAAU,WACnDjJ,IAAI0H,yBAECtb,EAAK,2BACV4T,IAAI/D,YACJ/f,MAAMsE,KAAO8E,8CAKd+M,UAAU+J,iBAAiB,YAAaJ,KAAK4L,gBAC7CvV,UAAU+J,iBAAiB,aAAcJ,KAAK6L,8CAG1C/F,MACHljB,GAASkjB,EAAEljB,OACbsqB,EAASlN,KAAKuE,WAAW6G,IAAI,aAAazD,MAC1CwF,EAAYnN,KAAKoN,oBACjBC,EAAarN,KAAKsN,kBACnBJ,EAAO/T,SAASvW,GAAS,IACvBgF,GAAIslB,EAAO1R,QAAQ5Y,QAClB2qB,WAAWF,EAAYF,GAAU,QACjCG,eAAiB1qB,OACjBwqB,oBAAsBxlB,OACtB2lB,WAAW3qB,EAAQgF,GAAG,EAAMke,aAE5B+F,uDAKD0B,WAAWvN,KAAKsN,eAAetN,KAAKoN,qBAAoB,UA/IzBjH,ysBCAhCqH,UAAYxO,oBAAsBC,oBAClCwO,WAAaD,UAGEE,+BACRtiB,EAAQ6C,uHACb7C,EAAQ6C,MACT7N,KAAO,YAEPutB,WAAa1f,EAAQ0f,YAAc,MAEpCC,IAAe,SAAU,UACzBC,EAAiBD,EAAYzU,SAASlL,EAAQ4f,gBAC/C5f,EAAQ4f,eAAiB,kBACvBC,oBAAsBF,EAAYpS,QAAQqS,KAE1ChO,sFAGM5R,MACP7K,GAAI4c,KAAKsC,cACRyL,gBAA8C,IAA5B9f,EAAQ8f,gBAAwB,EAAI,IAEzDxqB,SAASpC,IAAmB,EAAbssB,aACflqB,SAAS1B,OAAS,IAClB6B,aAA4B,EAAb+pB,aACf5K,WAAa4K,WAAa/V,mBACzBjU,eAAeL,MAEdS,GAAImc,KAAKzS,KACTygB,EAAUhO,KAAK+N,gBAAkB1G,kBAAoB,OACpDtD,kBAAoB5M,gBAAgBtT,EAAEK,MAAOL,EAAEuZ,KACjD4Q,GAAWR,UAAY7pB,cAAcP,4CAIpC4qB,GAAUhO,KAAK+N,gBAAkB1G,kBAAoB,EACrD4G,EAAYjO,KAAK8C,MAAMmL,UAAYjO,KAAK8C,MAAMmL,UAAY,QACzDpJ,WAAaoJ,EAAYD,GAAWR,UACtC7pB,cAAcqc,KAAKsC,mDAGX/U,0DAAKyS,KAAKzS,QAClBA,EAAKrJ,OAASqJ,EAAK6P,KAAO7P,EAAKrJ,MAAQqJ,EAAK6P,SACxC,IAAI0E,OAAM,kDAGbvU,EAAKrJ,UACHA,MAAQ,GAAI6B,QACZ7B,MAAMgqB,YAAa3gB,EAAKrJ,MAAMgT,cAAgB,IAEhD3J,EAAK6P,QAAYA,IAAM,GAAIrX,SAC1BooB,WAAa5gB,EAAK4gB,eAEpBvkB,SAASoP,OAAOxO,KAAK+C,EAAK4gB,YAAY,IAAM,IAAQ,IAClDxmB,aACG6C,KAAK+C,EAAK4gB,YAAYhL,QAAQ,eAChC3M,GAAO,GAAIzQ,MAAKqoB,EAAevW,gBAC5BhB,YAAYL,IAASjJ,EAAK4gB,WAAWC,OAExCD,WAAaxmB,QAGZ4F,qCAIHiZ,GAAIxG,KAAK8C,QAEX5e,MAAQ6R,MAAMiK,KAAKzS,KAAKrJ,SACxBkZ,IAAMrH,MAAMiK,KAAKzS,KAAK6P,OAEtBiR,eAAiBtY,MAAMyQ,EAAEtiB,SACzB+pB,UAAY9W,gBAAgBqP,EAAEtiB,MAAOsiB,EAAEpJ,OACvCZ,aAAeJ,iBAChBpD,OAAO4B,OAAOoF,KAAKzS,KAAK4gB,YAAapP,6BAEpCuP,cAAgBtO,KAAKuO,kEAInB/H,EAAIxG,KAAK8C,MACT0L,EAAUxO,KAAK+N,gBAAkB,EAAI,EAErC9U,EAAmBuN,EAAE8H,cAAc7jB,IAAI,SAAC4O,EAAQzR,UACnD,oBAEQyR,EAAO1J,eACJ6d,oBACCC,sBACCzO,2BACJsB,EAAKyB,aAAahd,QAAU,aACxByhB,EAAE8H,cACZpV,OAAO,SAACG,EAAQpW,SAAMA,GAAI2E,IAC1B6C,IAAI,kBAAU4O,GAAOoQ,KAAKtlB,OAASqqB,IACnC3lB,OAAO,SAACG,EAAGa,SAAMb,GAAIa,GAAG,GACvB2jB,WAEJ,iBACQhH,GAAE8H,cAAc1mB,IACtB6d,KAAKnF,WAIHiE,WAAa,GAAIW,KAAIjM,EACxBxO,IAAI,SAACkB,EAAM/D,MACPqjB,GAAYrS,+CAAgBjN,WACxBA,EAAK,GAAK,IAAM/D,EAAGqjB,SAIzB3kB,GAAI,kBACQ6c,QAAQ,SAACsL,EAAS7mB,OAC7B,EAAG,EAAG,GAAGuR,SAASvR,GAAI,IACrB8mB,GAAU3gB,SAAS,kBAAmByf,UAAU,EAAGlnB,EAAGmoB,YAE9CzP,uBACN,aACQ,UAGTwF,SAASjkB,YAAYmuB,MAEtBjB,4CAIAlgB,GACFA,WACK6Q,MAAM,2BAGV7Q,KAAOyS,KAAKgC,YAAYzU,QACxBgW,YACAU,oEAIA5N,UAAU+J,iBAAiB,YAAa,SAAC0F,KACxCvB,WAAWpB,QAAQ,eACnBwL,GAAaC,EAAKjH,MAClBkH,EAAY/I,EAAEljB,UACf+rB,EAAWxV,SAAS0V,GAAY,IAE9B5qB,GAAQ4qB,EAAU5c,aAAa,cAC/B6c,EAAYD,EAAU5c,aAAa,aAAaK,MAAM,KAEtD8F,EAAQL,aAAanO,SAASklB,EAAU,IAAI,GAAG,GAE/CzD,EAAOjE,EAAK/Q,UAAUnV,wBAAyBoqB,EAAOuD,EAAU3tB,wBAEhEoK,EAAQ1B,SAASkc,EAAEljB,OAAOqP,aAAa,UACvC3F,EAAIgf,EAAK/pB,KAAO8pB,EAAK9pB,KAAO+J,EAAM,EAClChF,EAAIglB,EAAKnqB,IAAMkqB,EAAKlqB,IACpB0E,EAAQ5B,EAAQ,IAAMmjB,EAAKuG,WAC3B9U,EAAO,OAAST,EAAQ,IAAM0W,EAAU,GAAK,KAAOA,EAAU,KAE7D9K,IAAIyH,UAAUnf,EAAGhG,GAAIuS,KAAMA,EAAMhT,MAAOA,EAAOib,WAAY,SAC3DkD,IAAI0H,sEAOP1G,WAAWgC,YAAc,MAC1B1a,GAAI,EACJhG,EAAImnB,WACJ1oB,EAASib,KAAK+B,aAAahd,QAAU,EAErCgqB,EAAWhhB,SAAS,iBAAkBzB,EAAGhG,EAAG,iBAEpC0Y,oBAAsB,KAC5B,MAGW,EAAZwO,UAAiBA,UAAU,OAC3BxI,WAAWzkB,YAAYwuB,QAEvBvP,OAAO1Y,MAAM,EAAGiY,2BAA2BtU,IAAI,SAACnB,EAAO1B,MACrDmiB,GAAS1c,WAAW,sBAAuBf,GAAKkhB,UAAY,GAAK5lB,EACtEtB,EAAG0Y,oBAAqBja,EAAQuE,KAC5B0b,WAAWzkB,YAAYwpB,QAIzBiF,GAAWjhB,SAAS,iBADRzB,EAAIyS,2BAA6ByO,UAAY,GAAKA,UAAU,EACvBlnB,EAAG,iBAE5C0Y,oBAAsB,KAC5B,SAGDgG,WAAWzkB,YAAYyuB,4CAaxB,GATAxI,GAAIxG,KAAK8C,SACoB0D,EAAEtiB,MAAM+S,WAAYuP,EAAEtiB,MAAMgT,eAAtD+X,OAAYC,UACU1I,EAAEpJ,IAAInG,WAAYuP,EAAEpJ,IAAIlG,eAE/CiY,OAAyBF,EAAa,EAA6B,SAAbC,GAExDZ,KAEAc,EAAerZ,MAAMyQ,EAAEtiB,OACnB0D,EAAI,EAAGA,EAAIunB,EAAYvnB,IAAK,IAC/ByP,GAAUmP,EAAEpJ,QACZtF,eAAesX,EAAc5I,EAAEpJ,KAAM,QACnBgS,EAAanY,WAAYmY,EAAalY,iBACjDiB,gCAEGtQ,KAAKmY,KAAKqP,gBAAgBD,EAAc/X,YAE9CA,EAAS,KACFA,QAGTiX,2CAGQlX,MAAWC,0DAAQ,MACbD,EAAUH,WAAYG,EAAUF,eAAhDkB,OAAOC,OACRiX,EAAc/X,eAAeH,GAG7BmY,SACInX,qBAHErC,MAAMsB,IAAYc,mBAAmBC,EAAOC,GAOrC,OAIb,GAHAmX,GAAiBrY,gBAAgBmY,EAAajY,GAE9CoS,KAAWjgB,SACP5B,EAAI,EAAGA,EAAI4nB,EAAgB5nB,MAC5BoY,KAAKyP,OAAOH,EAAalX,KAC1BvQ,KAAK2B,aAEI,GAAIzD,MAAKyD,EAAIkO,mBAAqB,GAAGmS,UAC9B,cAGuBrkB,KAA1CgE,EAAIkO,mBAAqB,GAAGoS,oBACtBwF,EAAa,KAChBznB,KAAKmY,KAAKyP,OAAOH,EAAalX,GAAO,OAG9BqR,KAAOA,EAEb8F,iCAGDnY,EAAWgB,OAOb,GAPoBsX,2DACpBlJ,EAAIxG,KAAK8C,MAGT6M,EAAc5Z,MAAMqB,GACpB5N,KAEI5B,EAAI,EAAGA,EAAI8P,mBAAoB9P,IAAK6Q,QAAQkX,EAAa,GAAI,IAChEtW,MAGAuW,EAAwBD,GAAenJ,EAAEtiB,OAASyrB,GAAenJ,EAAEpJ,GAEpEsS,IAASC,EAAY1Y,aAAemB,IAAUwX,IACzC/F,SAAWhT,YAAY8Y,KAErB3P,KAAK6P,mBAAmBF,KAE9B9nB,KAAKwR,SAGH7P,8CAGWgN,MACdqT,GAAWhT,YAAYL,GACvBsT,EAAY9J,KAAKzS,KAAK4gB,WAAWtE,mBAE1BA,YACCC,GAAa,OAClB9J,KAAKR,OAAO9C,iBAAiBoN,EAAW9J,KAAK8C,MAAMtG,uBAtRvBoF,0gBCFhB1D,iCACR9S,EAAQO,uHACbP,EAAQO,aAETqf,WAAarf,EAAKqf,iBAClB8E,YAAcnkB,EAAKmkB,kBAEnB1vB,KAAOuL,EAAKvL,MAAQ,SACpB+jB,KAAO,IAEPtE,wFAIFG,KAAKzS,KAAKuP,SAAS3Y,QAAU,SAC1BkV,OAAOsJ,WAAa,OACpBL,SAAS/e,SAAS1B,OAAS,sCAIxBoM,gGACOA,KAER8hB,YAAc9hB,EAAQ8hB,kBACtB1J,eAAiBpY,EAAQoY,wBAE5BhN,OAAO2W,UAAY/hB,EAAQ8hB,YAAYC,WAAa,YACpD3W,OAAO4W,UAAYhiB,EAAQ8hB,YAAYE,WAAa,YACpD5W,OAAO6W,UAAYjiB,EAAQ8hB,YAAYG,WAAa,OACpD7W,OAAO8W,oBAAsBliB,EAAQ8hB,YAAYI,qBAAuB,OAExE9W,OAAO+W,eAAiBniB,EAAQoY,eAAe+J,oBAC/C/W,OAAO+M,eAAiBnY,EAAQoY,eAAeD,oBAE/C/M,OAAOwR,iBAAmB5c,EAAQ4c,6DAIhClO,iEADSqD,KAAKzS,KACCyS,KAAK5f,uDAIpBid,qEADc2C,KAAKzS,wCAItB2W,gEACCmM,iBACDnM,QACEoM,oBAAoBtQ,KAAKuQ,gBAA+B,SAAdvQ,KAAK5f,WAEhDowB,8DAIDhK,GAAIxG,KAAK8C,MACTlG,EAASoD,KAAKzS,KAAKqP,SACrBC,cAAgBD,EAAOzY,SAEvBssB,UAAYzQ,KAAK1U,MAAOkb,EAAE3J,gBAE1B6T,QAAUlK,EAAEiK,UAAU,IAMtBE,cACO/T,YACGA,EAAOnS,IAAI,SAAC5G,EAAG+D,SACzBhE,UAAS4iB,EAAEkK,QAAU9oB,EAAI4e,EAAEiK,0DAKVG,MACbvV,GAAOV,mBAAmBiW,yDADa,SAEvC/U,EAAkBmE,KAAK3Z,OAASqV,cAAcL,GAC9CwV,EAAiBtV,gBAAgBF,GAAQQ,EACzCzV,EAAW4Z,KAAK3Z,OAAU+U,aAAaC,GAAQwV,OAEhD/N,MAAMlH,cACFP,YACGA,EAAK5Q,IAAI,kBAAKrE,GAAWvC,EAAIgY,oBACvBA,WACPzV,QAIN0qB,yBACAC,qBACAC,8DAIDxK,GAAIxG,KAAK8C,MACTmO,EAAW,kBAAUrW,GAAOnQ,IAAI,kBAAOkR,OAAMrR,EAAKkc,EAAE5K,YAEtDkB,SAAWkD,KAAKzS,KAAKuP,SAASrS,IAAI,SAAC5G,EAAG+D,MACnCgT,GAAS/W,EAAE+W,OACXsW,EAAertB,EAAEqtB,6BAEdrtB,EAAEgV,MAAQhV,EAAEgV,KAAKsY,QAAQ,SAAU,SAACC,SAAiB,KAARA,EAAc,QAAkB,KAARA,EAAc,OAAS,eAC3FxpB,YACI/D,EAAEoZ,iBAELrC,aACIqW,EAASrW,gBAEPsW,iBACED,EAASC,iDAMvB1K,GAAIxG,KAAK8C,SACV9C,KAAKgL,WAAWqG,sBAChBC,UAAY9K,EAAE1J,SAAS0J,EAAE1J,SAAS3Y,OAAS,GAAGotB,kBAG/CD,UAAY,GAAIjtB,OAAMmiB,EAAE3J,eAAerY,KAAK,QAC5CsY,SAASrS,IAAI,cACZyf,WAAWzf,IAAI,SAACwE,EAAKhM,GACnBgM,EAAMuX,EAAE8K,UAAUruB,OAClBquB,UAAUruB,GAAKgM,iDAOhBuX,GAAIxG,KAAK8C,KACV9C,MAAKzS,KAAKiQ,gBACPsF,MAAMtF,SAAWwC,KAAKzS,KAAKiQ,SAAS/S,IAAI,qBAC1C8d,SAAW5M,MAAM9X,EAAEgC,MAAO2gB,EAAE5K,OAC1B/X,EAAEoK,UAASpK,EAAEoK,YAIVpK,KAGNmc,KAAKzS,KAAK4P,gBACP2F,MAAM3F,SAAW6C,KAAKzS,KAAK4P,SAAS1S,IAAI,qBAC1Cse,SAAWpN,MAAM9X,EAAEK,MAAOsiB,EAAE5K,SAC5BoN,OAASrN,MAAM9X,EAAEuZ,IAAKoJ,EAAE5K,OACtB/X,EAAEoK,UAASpK,EAAEoK,YACVpK,0DAMLiC,EAAM,YAEPka,KAAKgL,WAAWqG,QAAS,GACrB,kBACFG,GAAa,GAAIntB,OAAM2b,KAAK8C,MAAMjG,eAAerY,KAAK,QACrD+I,KAAKuP,SAASrS,IAAI,SAAC5G,EAAG+D,MACtBgT,GAAS0F,EAAK/S,KAAKuP,SAASlV,GAAGgT,SACjC9U,GAAO0rB,EAAaA,EAAW/mB,IAAI,SAACyW,EAAGtZ,SAAMsZ,GAAItG,EAAOhT,UAIxD6pB,GAAgBzR,KAAKzS,KAAKuP,SAASrS,IAAI,kBAAK5G,GAAEiC,WAC/Cka,MAAKzS,KAAKiQ,YACE3V,KAAKmY,KAAKzS,KAAKiQ,SAAS/S,IAAI,kBAAK5G,GAAEgC,SAE/Cma,KAAKzS,KAAK4P,eACP5P,KAAK4P,SAAS1S,IAAI,cACR5C,MAAMhE,EAAEuZ,IAAKvZ,EAAEK,iBAIrBO,oCAAUgtB,yDAIhBxY,IAEF,cAEO+G,KAAK3G,OAAO4W,gBACXjQ,KAAK1U,qBACI0U,KAAK3G,OAAO8W,qBAG7B,iBACQnQ,MAAK8C,MAAMlH,OACjB6J,KAAKzF,QAIP,cAEOA,KAAK3G,OAAO2W,iBACVhQ,KAAK3Z,QAGd,cACKmgB,GAAIxG,KAAK8C,eACX6N,MAAM/H,WAAanL,mBAAmBuC,KAAK1U,MAC5Ckb,EAAEmK,MAAM/T,OAAQoD,KAAK3G,OAAO6W,WAEtB1J,EAAEmK,OACRlL,KAAKzF,QAIP,kBAEQA,KAAK1U,UACP,SAEN,iBACQ0U,MAAK8C,MAAM3F,UACjBsI,KAAKzF,QAIL0R,EAAc1R,KAAK8C,MAAMhG,SAAS5D,OAAO,kBAAqB,QAAhBrV,EAAEoZ,YAChD0U,EAAe3R,KAAK8C,MAAMhG,SAAS5D,OAAO,kBAAqB,SAAhBrV,EAAEoZ,YAEjD2U,EAAcF,EAAYjnB,IAAI,eAC7BkF,GAAQ9L,EAAE8L,aAEb,YAAmB9L,EAAE8L,aAEbA,QACAyX,EAAK5H,OAAO7P,WACVyX,EAAK4D,WAAWqG,yBAGPjK,EAAK/N,OAAOwR,2BACnBzD,EAAK/gB,OAASsY,wBAE1B,cACK6H,GAAIxG,KAAK8C,MACTjf,EAAI2iB,EAAE1J,SAASnN,GACf0hB,EAAUrR,KAAKgL,WAAWqG,QAE1BQ,EAAa7R,KAAKgL,WAAW6G,YAAcnT,sBAC3C0L,EAAY5D,EAAEiK,WAAa,EAAIoB,GAC/B3K,EAAWkD,GAAWiH,EAAU,EAAIK,EAAYvtB,QAEhD+jB,EAAa1B,EAAEmK,MAAMrI,UAAU7d,IAAI,kBAAK6B,GAAI8d,EAAU,GACtDiH,OACUnJ,EAAWzd,IAAI,kBAAKvD,GAAIggB,EAAWvX,QAG7CiN,GAAS,GAAIvY,OAAMmiB,EAAE3J,eAAerY,KAAK,GAC1Cwb,MAAK3G,OAAOwR,qBACXwG,GAAWxtB,EAAE8L,QAAU6W,EAAE1J,SAAS3Y,OAAS,EACpCN,EAAEqtB,aAEFrtB,EAAE+W,WAITuP,GAAU,GAAI9lB,OAAMmiB,EAAE3J,eAAerY,KAAK,SAC3C6sB,OACQxtB,EAAEqmB,WAAWzf,IAAI,SAACnE,EAAGrD,SAAMqD,GAAIzC,EAAE0tB,eAAetuB,kBAI9CilB,aACArkB,EAAEqmB,mBACLC,SAEDvN,WAEE4J,EAAE5K,MAAMxV,mBACPgkB,WACDlD,IAEVzB,KAAK2B,MAIL0K,EAAcH,EAAalnB,IAAI,eAC9BkF,GAAQ9L,EAAE8L,aAEb,aAAoB9L,EAAE8L,aAEdA,QACAyX,EAAK5H,OAAO7P,WACVyX,EAAK7W,iBACJ6W,EAAK0I,YAAYzf,oBACf+W,EAAK0I,YAAYrf,kBACrB2W,EAAK0I,YAAY3f,gBACfiX,EAAK0I,YAAYlF,kBACjBxD,EAAK0I,YAAYnF,0BAGTvD,EAAK/N,OAAOwR,kBAE/B,cACKrE,GAAIxG,KAAK8C,MACTjf,EAAI2iB,EAAE1J,SAASnN,GACfoiB,EAAUvL,EAAE5K,MAAM0M,UAAU,GAAK9B,EAAE5K,MAAMxV,SAC1CogB,EAAE5K,MAAM0M,UAAU,GAAK9B,EAAE5K,MAAMxV,2BAGrBogB,EAAEmK,MAAMrI,qBACRzkB,EAAEqmB,kBAENrmB,EAAE+W,gBAEAmX,SACF/R,KAAK8P,YAAYkC,SAAWpT,sBAEpC6G,KAAK2B,MAIL6K,IAEF,kBAEQjS,KAAK1U,UACP,SAEN,iBACQ0U,MAAK8C,MAAMtF,UACjBiI,KAAKzF,UAIU/G,EAAiBxU,OAAOmtB,EAAaE,EAAaG,MAEjEC,IAAa,WAAY,iBACxBC,2BAEA5N,WAAa,GAAIW,KAAIjM,EACxBC,OAAO,mBAASgZ,EAAU/Y,SAASxN,EAAK,KAAOyb,EAAKtE,MAAMnX,EAAK,MAC/DlB,IAAI,eACAwgB,GAAYrS,+CAAgBjN,WAC7BA,EAAK,GAAGwN,SAAS,cAAgBxN,EAAK,GAAGwN,SAAS,gBAC/CgZ,mBAAmBtqB,KAAKojB,IAEtBtf,EAAK,GAAIsf,gEAKdmH,kBAED5L,GAAIxG,KAAK8C,MACTuP,EAAUrS,KAAK3G,OAAO+W,eACtBkC,EAAUtS,KAAK3G,OAAO+M,cACbI,GAAEmK,MAAM/T,OAEdnS,IAAI,SAACzD,EAAO2I,MACdiL,GAASmL,EAAKjD,MAAMhG,SAASrS,IAAI,SAAC4V,EAAKzY,MACtC/B,GAAQwa,EAAIzF,OAAOjL,gBAEf0Q,EAAIxH,WACJhT,OACDwa,EAAI6J,WAAWva,SACdoW,EAAKvG,OAAO5X,aACR0qB,EAAUA,EAAQzsB,GAASA,OAInCusB,YAAYziB,UACT3I,iBACSqrB,EAAUA,EAAQrrB,GAASA,OACrCwf,EAAEmK,MAAMrI,UAAU3Y,UAChBiL,WACE4L,EAAE8K,UAAU3hB,4DAOnB0G,UAAU+J,iBAAiB,YAAa,SAAC0F,MACzC1iB,GAAIylB,EAAKvG,SACT5Z,EAAI3H,UAAU8nB,EAAKxS,WACnBkc,EAAOzM,EAAEgH,MAAQpkB,EAAEnH,KAAOiC,cAAcJ,GACxCovB,EAAO1M,EAAEiH,MAAQrkB,EAAEvH,GAEpBqxB,GAAO3J,EAAKxiB,OAASlD,aAAaC,IACjCovB,EAAQrvB,aAAaC,KACnBqvB,oBAAoBF,KAEpBvO,IAAI/D,wDAKQsS,MACf/L,GAAIxG,KAAK8C,SACT0D,EAAE8K,cAEF3hB,GAAQmM,kBAAkByW,EAAM/L,EAAEmK,MAAMrI,WAAW,MACnD3Y,GAAS,EAAG,IACX+iB,GAAM1S,KAAKoS,YAAYziB,QAEtBqU,IAAIyH,UACRiH,EAAIxH,KAAOlL,KAAKgE,IAAI/Y,OAAOqB,EAC3BomB,EAAIC,SAAW3S,KAAKgE,IAAI/Y,OAAO3E,GAC9BuS,KAAM6Z,EAAIE,eAAgB/sB,MAAO,IAClC6sB,EAAI9X,OACJjL,QAGIqU,IAAI0H,8DAKNlF,EAAIxG,KAAKzS,IACViZ,GAAE1J,SAAS3Y,OAAS,SACjB6gB,WAAWgC,YAAc,KAC5BlK,SAASrS,IAAI,SAAC5G,EAAG+D,MACdsf,GAAWzI,qBAGXxd,EAAOuM,YAEC5F,EACX,IACAsf,EACA+B,EAAKzJ,OAAO5X,GACZ/D,EAAEgV,KACFoQ,EAAK5P,OAAOgJ,mBACR2C,WAAWzkB,YAAYU,0DAS3B+e,KAAKmE,sBACFA,KAAO,EAGVnE,MAAK6S,oBACFA,cAAc1P,QAAQ,eACtBza,GAAIoB,EAAEwX,UACR/W,WAAWyK,YAAYtM,UAItBmqB,cAAgB7S,KAAKmS,mBAAmB1nB,IAAI,wBAEzCyW,EAAE8I,qBACCxkB,SACF0b,EAAE+I,aAIoBzkB,KAA5Bwa,KAAK8C,MAAMgQ,oBACRhQ,MAAMgQ,aAAe9S,KAAK8C,MAAMjG,cAAgB,QAIjDgW,cAAcpoB,IAAI,eAClBsoB,GAAclvB,EAAEomB,MAAM+I,EAAKlQ,MAAMgQ,gBAEnCxR,QAAUF,YAAYvd,EAAEzD,MAAM2yB,KAC3BvO,SAASjkB,YAAYsD,EAAEyd,yDAK1BtB,KAAK6S,oBACFA,cAAc1P,QAAQ,eACtBza,GAAIoB,EAAEwX,UACR/W,WAAWyK,YAAYtM,2DAMtB0C,OAAOgV,iBAAiB,cAAe,aACtCmB,sEAKD4Q,mBAAmB1nB,IAAI,cACzBwf,MAAMxf,IAAI,cACN2V,iBAAiB,QAAS,cAC1BzQ,GAAQiB,EAAKqB,aAAa,sBACzBghB,oBAAoBtjB,cAMvBqU,IAAI3N,UAAU+J,iBAAiB,QAAS,cACxCzQ,GAAQujB,EAAKlP,IAAI3N,UAAUpE,aAAa,sBACvCghB,oBAAoBtjB,6DAKrBkjB,cAAcpoB,IAAI,eAClBsoB,GAAclvB,EAAEomB,MAAMkJ,EAAKrQ,MAAMgQ,4BACvBjvB,EAAEzD,MAAM2yB,EAAalvB,EAAEyd,sDAKjC2R,oBAAoBjT,KAAK8C,MAAMgQ,aAAe,+CAI9CG,oBAAoBjT,KAAK8C,MAAMgQ,aAAe,6CAGvCnjB,0DAAMqQ,KAAK8C,MAAMgQ,aACzBtM,EAAIxG,KAAK8C,mBAELnT,QACA6W,EAAEmK,MAAM/T,OAAOjN,UACd6W,EAAE1J,SAASrS,IAAI,kBAAK5G,GAAE+W,OAAOjL,kDAKnBA,MACf6W,GAAIxG,KAAK8C,SACLlZ,SAAS+F,IACN,IAAGA,EAAQ,GACnBA,GAAS6W,EAAEmK,MAAM/T,OAAOzY,SAAQwL,EAAQ6W,EAAEmK,MAAM/T,OAAOzY,OAAS,GAChEwL,IAAU6W,EAAEsM,iBACbA,aAAenjB,OACZqQ,KAAK5U,OAAQ,cAAe4U,KAAKoT,sDAM1BpsB,EAAOqsB,MAAe1jB,0DAAMqQ,KAAK8C,MAAMjG,8GAChC7V,EAAOqsB,EAAe1jB,QACpCpC,KAAKqP,OAAO0W,OAAO3jB,EAAO,EAAG3I,QAC7BuG,KAAKuP,SAASrS,IAAI,SAAC5G,EAAG+D,KACxBgT,OAAO0Y,OAAO3jB,EAAO,EAAG0jB,EAAczrB,WAEpC8c,OAAO1E,KAAKzS,mDAGFoC,0DAAQqQ,KAAK8C,MAAMjG,cAAc,CAC5CmD,MAAKzS,KAAKqP,OAAOzY,QAAU,uGAGTwL,QACjBpC,KAAKqP,OAAO0W,OAAO3jB,EAAO,QAC1BpC,KAAKuP,SAASrS,IAAI,cACpBmQ,OAAO0Y,OAAO3jB,EAAO,UAEnB+U,OAAO1E,KAAKzS,6CAGJ8lB,MAAe1jB,0DAAM,OAC7BpC,KAAKuP,SAASnN,GAAOiL,OAASyY,OAC9B3O,OAAO1E,KAAKzS,6CAKHuP,QACTvP,KAAKuP,SAASrS,IAAI,SAAC5G,EAAG+D,GACvBkV,EAASlV,OACTgT,OAASkC,EAASlV,WAGjB8c,OAAO1E,KAAKzS,aA5jBoBqU,0gBCFlB2R,kCACRnoB,EAAQO,uHACbP,EAAQO,aACTvL,KAAO,UACP2iB,YAAc,IACdoB,KAAO,IAEPtE,oFAGIlU,gGACOA,QACXigB,UAAY5L,KAAK4L,UAAUnG,KAAKzF,WAChC6L,WAAa7L,KAAK6L,WAAWpG,KAAKzF,WAElC8L,WAAangB,EAAKmgB,YAAc,QAChCzS,OAAO0S,WAAapgB,EAAKogB,YAAc,OAEvC5f,UAAYR,EAAKQ,YAAa,OAC9B4b,YAAcpc,EAAKoc,aAAe,yIAKnCvB,GAAIxG,KAAK8C,WACR/d,OACJib,KAAK3Z,OAAS2Z,KAAK1U,MAChB0U,KAAK9T,OAAOI,EAAI0T,KAAK+H,YAAc,EACnC/H,KAAK9T,OAAO5F,EAAI0Z,KAAK+H,YAAc,KAE/BhjB,GAAsBib,KAAtBjb,OAAQoH,EAAc6T,KAAd7T,UAEV6f,EAAuBxF,EAAEyF,uBAC7BnE,kBACAmE,uBACEC,GAAW,IAAMlM,KAAK3G,OAAO0S,aAE/BtF,YAAYhc,IAAI,SAACkc,EAAO/e,MACnBmkB,GAAaG,EACbC,EAAmBxF,EAAQH,EAAEO,WAAczH,WAC3ClT,EAAW+f,EAAkB,IAAM,EAAG,EACtCC,EAAYjgB,GAAaggB,EAAkBA,EAC3CE,EAAWH,GAAsBE,EACjCpgB,EAAgBnH,mBAAmBknB,EAAYhnB,GAC/CkH,EAAcpH,mBAAmBwnB,EAAUtnB,GAE3CunB,EAAehM,EAAK6D,MAAQ6H,EAAqBpkB,GAEnD2kB,SAASC,QACVlM,GAAK6D,QACImI,EAAeA,EAAatgB,cAAgBA,IAC9CsgB,EAAeA,EAAargB,YAAcD,MAExCA,IACFC,MAEJwgB,GACe,MAApBN,EACGtf,oBAAoB0f,EAAUC,EAAQlM,EAAKpU,OAAQoU,EAAKvb,OAAQub,EAAKnU,UAAWC,GAChFQ,qBAAqB2f,EAAUC,EAAQlM,EAAKpU,OAAQoU,EAAKvb,OAAQub,EAAKnU,UAAWC,KAEnF0b,aAAajgB,KAAK4kB,KAClBR,iBAAiBpkB,0CAGX8e,QACAH,EAAEO,yCAGFqF,WAIJjI,KAAO,+CAIRqC,GAAIxG,KAAK8C,MAET7J,IAEF,iBAEA,+BAEgBuN,EAAEsB,oBACR9H,KAAKR,mBACAQ,KAAK+H,cAElBtC,KAAKzF,aAIJuE,WAAa,GAAIW,KAAIjM,EACxBxO,IAAI,eACAwgB,GAAYrS,+CAAgBjN,WACxBA,EAAK,GAAIsf,kDAIAyB,MACZ3nB,GAAuBib,KAAvBjb,OAAQ+mB,EAAe9L,KAAf8L,WACTvD,EAAW1jB,mBAAmB6nB,EAASX,WAAYW,EAAS5nB,MAAQ,EAAGC,wBACtDwjB,EAASjc,EAAKwf,QAAiBvD,EAASjiB,EAAKwlB,6CAG1D1b,EAAKxI,EAAE+kB,EAAK7G,MAClB1V,MACE9G,GAAQ0W,KAAKR,OAAO5X,MACvB+kB,EAAM,WACEvc,EAAM4P,KAAK4M,oBAAoB5M,KAAK8C,MAAMmJ,iBAAiBrkB,OAChE1H,MAAMsO,OAASnF,mBAAmBC,EAAO,OAC1CujB,GAAQ9rB,UAAUif,KAAKlK,KACvBxJ,EAAIwZ,EAAEgH,MAAQD,EAAMtrB,KAAO,GAC3B+E,EAAIwf,EAAEiH,MAAQF,EAAM1rB,IAAM,GAC1B+e,GAASF,KAAKgN,kBAAoBhN,KAAKgN,iBAAiB7oB,OAAS,EAClE6b,KAAKgN,iBAAiBplB,GAAKoY,KAAK8C,MAAMlG,OAAOhV,IAAM,KAClDqlB,GAAuC,IAA5BjN,KAAK8C,MAAM2D,YAAY7e,GAAWoY,KAAK8C,MAAMiE,YAAYjjB,QAAQ,QAC3EkgB,IAAIyH,UAAUnf,EAAGhG,GAAIuS,KAAMqH,EAAOra,MAAOonB,EAAU,WACnDjJ,IAAI0H,yBAECtb,EAAK,2BACV4T,IAAI/D,YACJ/f,MAAMsO,OAASlF,8CAKhB+M,UAAU+J,iBAAiB,YAAaJ,KAAK4L,gBAC7CvV,UAAU+J,iBAAiB,aAAcJ,KAAK6L,8CAG1C/F,MACHljB,GAASkjB,EAAEljB,OACbsqB,EAASlN,KAAKuE,WAAW6G,IAAI,eAAezD,MAC5CwF,EAAYnN,KAAKoN,oBACjBC,EAAarN,KAAKsN,kBACnBJ,EAAO/T,SAASvW,GAAS,IACvBgF,GAAIslB,EAAO1R,QAAQ5Y,QAClB2qB,WAAWF,EAAYF,GAAU,QACjCG,eAAiB1qB,OACjBwqB,oBAAsBxlB,OACtB2lB,WAAW3qB,EAAQgF,GAAG,EAAMke,aAE5B+F,uDAKD0B,WAAWvN,KAAKsN,eAAetN,KAAKoN,qBAAoB,UArJvBjH,kBTAlChI,gBACAD,eACCA,qBAEM6M,wBACH2C,YACJ/B,eACE4H,YAiBFC,MACL,WAAYpoB,EAAQ6C,kCACZgQ,eAAehQ,EAAQ7N,KAAMgL,EAAQ6C"} \ No newline at end of file diff --git a/node_modules/frappe-charts/dist/frappe-charts.min.esm.js b/node_modules/frappe-charts/dist/frappe-charts.min.esm.js deleted file mode 100644 index 29a33d1..0000000 --- a/node_modules/frappe-charts/dist/frappe-charts.min.esm.js +++ /dev/null @@ -1,2 +0,0 @@ -function styleInject(t,e){void 0===e&&(e={});var n=e.insertAt;if(t&&"undefined"!=typeof document){var i=document.head||document.getElementsByTagName("head")[0],a=document.createElement("style");a.type="text/css","top"===n&&i.firstChild?i.insertBefore(a,i.firstChild):i.appendChild(a),a.styleSheet?a.styleSheet.cssText=t:a.appendChild(document.createTextNode(t))}}function $(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function getOffset(t){var e=t.getBoundingClientRect();return{top:e.top+(document.documentElement.scrollTop||document.body.scrollTop),left:e.left+(document.documentElement.scrollLeft||document.body.scrollLeft)}}function isHidden(t){return null===t.offsetParent}function isElementInViewport(t){var e=t.getBoundingClientRect();return e.top>=0&&e.left>=0&&e.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&e.right<=(window.innerWidth||document.documentElement.clientWidth)}function getElementContentWidth(t){var e=window.getComputedStyle(t),n=parseFloat(e.paddingLeft)+parseFloat(e.paddingRight);return t.clientWidth-n}function fire(t,e,n){var i=document.createEvent("HTMLEvents");i.initEvent(e,!0,!0);for(var a in n)i[a]=n[a];return t.dispatchEvent(i)}function getTopOffset(t){return t.titleHeight+t.margins.top+t.paddings.top}function getLeftOffset(t){return t.margins.left+t.paddings.left}function getExtraHeight(t){return t.margins.top+t.margins.bottom+t.paddings.top+t.paddings.bottom+t.titleHeight+t.legendHeight}function getExtraWidth(t){return t.margins.left+t.margins.right+t.paddings.left+t.paddings.right}function _classCallCheck$4(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function floatTwo(t){return parseFloat(t.toFixed(2))}function fillArray(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]&&arguments[3];n||(n=i?t[0]:t[t.length-1]);var a=new Array(Math.abs(e)).fill(n);return t=i?a.concat(t):t.concat(a)}function getStringWidth(t,e){return(t+"").length*e}function getPositionByAngle(t,e){return{x:Math.sin(t*ANGLE_RATIO)*e,y:Math.cos(t*ANGLE_RATIO)*e}}function isValidNumber(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return!Number.isNaN(t)&&(void 0!==t&&(!!Number.isFinite(t)&&!(e&&t<0)))}function round(t){return Number(Math.round(t+"e4")+"e-4")}function deepClone(t){var e=void 0,n=void 0,i=void 0;if(t instanceof Date)return new Date(t.getTime());if("object"!==(void 0===t?"undefined":_typeof$2(t))||null===t)return t;e=Array.isArray(t)?[]:{};for(i in t)n=t[i],e[i]=deepClone(n);return e}function getBarHeightAndYAttr(t,e){var n=void 0,i=void 0;return t<=e?(n=e-t,i=t):(n=t-e,i=e),[n,i]}function equilizeNoOfElements(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:e.length-t.length;return n>0?t=fillArray(t,n):e=fillArray(e,n),[t,e]}function truncateString(t,e){if(t)return t.length>e?t.slice(0,e-3)+"...":t}function shortenLargeNumber(t){var e=void 0;if("number"==typeof t)e=t;else if("string"==typeof t&&(e=Number(t),Number.isNaN(e)))return t;var n=Math.floor(Math.log10(Math.abs(e)));if(n<=2)return e;var i=Math.floor(n/3),a=Math.pow(10,n-3*i)*+(e/Math.pow(10,n)).toFixed(1);return Math.round(100*a)/100+" "+["","K","M","B","T"][i]}function getSplineCurvePointsStr(t,e){for(var n=[],i=0;i255?255:t<0?0:t}function lightenDarkenColor(t,e){var n=getColor(t),i=!1;"#"==n[0]&&(n=n.slice(1),i=!0);var a=parseInt(n,16),r=limitColor((a>>16)+e),o=limitColor((a>>8&255)+e),s=limitColor((255&a)+e);return(i?"#":"")+(s|o<<8|r<<16).toString(16)}function isValidColor(t){var e=/(^\s*)(rgb|hsl)(a?)[(]\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*(?:,\s*([\d.]+)\s*)?[)]$/i;return/(^\s*)(#)((?:[A-Fa-f0-9]{3}){1,2})$/i.test(t)||e.test(t)}function $$1(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function createSVG(t,e){var n=document.createElementNS("http://www.w3.org/2000/svg",t);for(var i in e){var a=e[i];if("inside"===i)$$1(a).appendChild(n);else if("around"===i){var r=$$1(a);r.parentNode.insertBefore(n,r),n.appendChild(r)}else"styles"===i?"object"===(void 0===a?"undefined":_typeof$1(a))&&Object.keys(a).map(function(t){n.style[t]=a[t]}):("className"===i&&(i="class"),"innerHTML"===i?n.textContent=a:n.setAttribute(i,a))}return n}function renderVerticalGradient(t,e){return createSVG("linearGradient",{inside:t,id:e,x1:0,x2:0,y1:0,y2:1})}function setGradientStop(t,e,n,i){return createSVG("stop",{inside:t,style:"stop-color: "+n,offset:e,"stop-opacity":i})}function makeSVGContainer(t,e,n,i){return createSVG("svg",{className:e,inside:t,width:n,height:i})}function makeSVGDefs(t){return createSVG("defs",{inside:t})}function makeSVGGroup(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0,i={className:t,transform:e};return n&&(i.inside=n),createSVG("g",i)}function makePath(t){return createSVG("path",{className:arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",d:t,styles:{stroke:arguments.length>2&&void 0!==arguments[2]?arguments[2]:"none",fill:arguments.length>3&&void 0!==arguments[3]?arguments[3]:"none","stroke-width":arguments.length>4&&void 0!==arguments[4]?arguments[4]:2}})}function makeArcPathStr(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=n.x+t.x,s=n.y+t.y,l=n.x+e.x,u=n.y+e.y;return"M"+n.x+" "+n.y+"\n\t\tL"+o+" "+s+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+u+" z"}function makeCircleStr(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=n.x+t.x,s=n.y+t.y,l=n.x+e.x,u=2*n.y,c=n.y+e.y;return"M"+n.x+" "+n.y+"\n\t\tL"+o+" "+s+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+u+" z\n\t\tL"+o+" "+u+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+c+" z"}function makeArcStrokePathStr(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=n.x+t.x,s=n.y+t.y,l=n.x+e.x,u=n.y+e.y;return"M"+o+" "+s+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+u}function makeStrokeCircleStr(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=n.x+t.x,s=n.y+t.y,l=n.x+e.x,u=2*i+s,c=n.y+t.y;return"M"+o+" "+s+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+u+"\n\t\tM"+o+" "+u+"\n\t\tA "+i+" "+i+" 0 "+r+" "+(a?1:0)+"\n\t\t"+l+" "+c}function makeGradient(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i="path-fill-gradient-"+e+"-"+(n?"lighter":"default"),a=renderVerticalGradient(t,i),r=[1,.6,.2];return n&&(r=[.4,.2,0]),setGradientStop(a,"0%",e,r[0]),setGradientStop(a,"50%",e,r[1]),setGradientStop(a,"100%",e,r[2]),i}function percentageBar(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:PERCENTAGE_BAR_DEFAULT_DEPTH,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:"none";return createSVG("rect",{className:"percentage-bar",x:t,y:e,width:n,height:i,fill:r,styles:{stroke:lightenDarkenColor(r,-25),"stroke-dasharray":"0, "+(i+n)+", "+n+", "+i,"stroke-width":a}})}function heatSquare(t,e,n,i,a){var r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:"none",o=arguments.length>6&&void 0!==arguments[6]?arguments[6]:{},s={className:t,x:e,y:n,width:i,height:i,rx:a,fill:r};return Object.keys(o).map(function(t){s[t]=o[t]}),createSVG("rect",s)}function legendBar(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"none",a=arguments[4];a=arguments.length>5&&void 0!==arguments[5]&&arguments[5]?truncateString(a,LABEL_MAX_CHARS):a;var r={className:"legend-bar",x:0,y:0,width:n,height:"2px",fill:i},o=createSVG("text",{className:"legend-dataset-text",x:0,y:0,dy:2*FONT_SIZE+"px","font-size":1.2*FONT_SIZE+"px","text-anchor":"start",fill:FONT_FILL,innerHTML:a}),s=createSVG("g",{transform:"translate("+t+", "+e+")"});return s.appendChild(createSVG("rect",r)),s.appendChild(o),s}function legendDot(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"none",a=arguments[4];a=arguments.length>5&&void 0!==arguments[5]&&arguments[5]?truncateString(a,LABEL_MAX_CHARS):a;var r={className:"legend-dot",cx:0,cy:0,r:n,fill:i},o=createSVG("text",{className:"legend-dataset-text",x:0,y:0,dx:FONT_SIZE+"px",dy:FONT_SIZE/3+"px","font-size":1.2*FONT_SIZE+"px","text-anchor":"start",fill:FONT_FILL,innerHTML:a}),s=createSVG("g",{transform:"translate("+t+", "+e+")"});return s.appendChild(createSVG("circle",r)),s.appendChild(o),s}function makeText(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},r=a.fontSize||FONT_SIZE;return createSVG("text",{className:t,x:e,y:n,dy:(void 0!==a.dy?a.dy:r/2)+"px","font-size":r+"px",fill:a.fill||FONT_FILL,"text-anchor":a.textAnchor||"start",innerHTML:i})}function makeVertLine(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};a.stroke||(a.stroke=BASE_LINE_COLOR);var r=createSVG("line",{className:"line-vertical "+a.className,x1:0,x2:0,y1:n,y2:i,styles:{stroke:a.stroke}}),o=createSVG("text",{x:0,y:n>i?n+LABEL_MARGIN:n-LABEL_MARGIN-FONT_SIZE,dy:FONT_SIZE+"px","font-size":FONT_SIZE+"px","text-anchor":"middle",innerHTML:e+""}),s=createSVG("g",{transform:"translate("+t+", 0)"});return s.appendChild(r),s.appendChild(o),s}function makeHoriLine(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};a.stroke||(a.stroke=BASE_LINE_COLOR),a.lineType||(a.lineType=""),a.shortenNumbers&&(e=shortenLargeNumber(e));var r=createSVG("line",{className:"line-horizontal "+a.className+("dashed"===a.lineType?"dashed":""),x1:n,x2:i,y1:0,y2:0,styles:{stroke:a.stroke}}),o=createSVG("text",{x:n3&&void 0!==arguments[3]?arguments[3]:{};isValidNumber(t)||(t=0),i.pos||(i.pos="left"),i.offset||(i.offset=0),i.mode||(i.mode="span"),i.stroke||(i.stroke=BASE_LINE_COLOR),i.className||(i.className="");var a=-1*AXIS_TICK_LENGTH,r="span"===i.mode?n+AXIS_TICK_LENGTH:0;return"tick"===i.mode&&"right"===i.pos&&(a=n+AXIS_TICK_LENGTH,r=n),a+=i.offset,r+=i.offset,makeHoriLine(t,e,a,r,{stroke:i.stroke,className:i.className,lineType:i.lineType,shortenNumbers:i.shortenNumbers})}function xLine(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};isValidNumber(t)||(t=0),i.pos||(i.pos="bottom"),i.offset||(i.offset=0),i.mode||(i.mode="span"),i.stroke||(i.stroke=BASE_LINE_COLOR),i.className||(i.className="");var a=n+AXIS_TICK_LENGTH,r="span"===i.mode?-1*AXIS_TICK_LENGTH:n;return"tick"===i.mode&&"top"===i.pos&&(a=-1*AXIS_TICK_LENGTH,r=0),makeVertLine(t,e,a,r,{stroke:i.stroke,className:i.className,lineType:i.lineType})}function yMarker(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};i.labelPos||(i.labelPos="right");var a=createSVG("text",{className:"chart-label",x:"left"===i.labelPos?LABEL_MARGIN:n-getStringWidth(e,5)-LABEL_MARGIN,y:0,dy:FONT_SIZE/-2+"px","font-size":FONT_SIZE+"px","text-anchor":"start",innerHTML:e+""}),r=makeHoriLine(t,"",0,n,{stroke:i.stroke||BASE_LINE_COLOR,className:i.className||"",lineType:i.lineType});return r.appendChild(a),r}function yRegion(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},r=t-e,o=createSVG("rect",{className:"bar mini",styles:{fill:"rgba(228, 234, 239, 0.49)",stroke:BASE_LINE_COLOR,"stroke-dasharray":n+", "+r},x:0,y:0,width:n,height:r});a.labelPos||(a.labelPos="right");var s=createSVG("text",{className:"chart-label",x:"left"===a.labelPos?LABEL_MARGIN:n-getStringWidth(i+"",4.5)-LABEL_MARGIN,y:0,dy:FONT_SIZE/-2+"px","font-size":FONT_SIZE+"px","text-anchor":"start",innerHTML:i+""}),l=createSVG("g",{transform:"translate(0, "+e+")"});return l.appendChild(o),l.appendChild(s),l}function datasetBar(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"",r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=arguments.length>6&&void 0!==arguments[6]?arguments[6]:0,s=arguments.length>7&&void 0!==arguments[7]?arguments[7]:{},l=getBarHeightAndYAttr(e,s.zeroLine),u=_slicedToArray(l,2),c=u[0],h=u[1];h-=o,0===c&&(c=s.minHeight,h-=s.minHeight),isValidNumber(t)||(t=0),isValidNumber(h)||(h=0),isValidNumber(c,!0)||(c=0),isValidNumber(n,!0)||(n=0);var d=createSVG("rect",{className:"bar mini",style:"fill: "+i,"data-point-index":r,x:t,y:h,width:n,height:c});if((a+="")||a.length){d.setAttribute("y",0),d.setAttribute("x",0);var f=createSVG("text",{className:"data-point-value",x:n/2,y:0,dy:FONT_SIZE/2*-1+"px","font-size":FONT_SIZE+"px","text-anchor":"middle",innerHTML:a}),p=createSVG("g",{"data-point-index":r,transform:"translate("+t+", "+h+")"});return p.appendChild(d),p.appendChild(f),p}return d}function datasetDot(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"",r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,o=createSVG("circle",{style:"fill: "+i,"data-point-index":r,cx:t,cy:e,r:n});if((a+="")||a.length){o.setAttribute("cy",0),o.setAttribute("cx",0);var s=createSVG("text",{className:"data-point-value",x:0,y:0,dy:FONT_SIZE/2*-1-n+"px","font-size":FONT_SIZE+"px","text-anchor":"middle",innerHTML:a}),l=createSVG("g",{"data-point-index":r,transform:"translate("+t+", "+e+")"});return l.appendChild(o),l.appendChild(s),l}return o}function getPaths(t,e,n){var i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},r=e.map(function(e,n){return t[n]+","+e}).join("L");i.spline&&(r=getSplineCurvePointsStr(t,e));var o=makePath("M"+r,"line-graph-path",n);if(i.heatline){var s=makeGradient(a.svgDefs,n);o.style.stroke="url(#"+s+")"}var l={path:o};if(i.regionFill){var u=makeGradient(a.svgDefs,n,!0),c="M"+t[0]+","+a.zeroLine+"L"+r+"L"+t.slice(-1)[0]+","+a.zeroLine;l.region=makePath(c,"region-fill","none","url(#"+u+")")}return l}function translate(t,e,n,i){var a="string"==typeof e?e:e.join(", ");return[t,{transform:n.join(", ")},i,STD_EASING,"translate",{transform:a}]}function translateVertLine(t,e,n){return translate(t,[n,0],[e,0],MARKER_LINE_ANIM_DUR)}function translateHoriLine(t,e,n){return translate(t,[0,n],[0,e],MARKER_LINE_ANIM_DUR)}function animateRegion(t,e,n,i){var a=e-n,r=t.childNodes[0];return[[r,{height:a,"stroke-dasharray":r.getAttribute("width")+", "+a},MARKER_LINE_ANIM_DUR,STD_EASING],translate(t,[0,i],[0,n],MARKER_LINE_ANIM_DUR)]}function animateBar(t,e,n,i){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0,r=getBarHeightAndYAttr(n,(arguments.length>5&&void 0!==arguments[5]?arguments[5]:{}).zeroLine),o=_slicedToArray$2(r,2),s=o[0],l=o[1];return l-=a,"rect"!==t.nodeName?[[t.childNodes[0],{width:i,height:s},UNIT_ANIM_DUR,STD_EASING],translate(t,t.getAttribute("transform").split("(")[1].slice(0,-1),[e,l],MARKER_LINE_ANIM_DUR)]:[[t,{width:i,height:s,x:e,y:l},UNIT_ANIM_DUR,STD_EASING]]}function animateDot(t,e,n){return"circle"!==t.nodeName?[translate(t,t.getAttribute("transform").split("(")[1].slice(0,-1),[e,n],MARKER_LINE_ANIM_DUR)]:[[t,{cx:e,cy:n},UNIT_ANIM_DUR,STD_EASING]]}function animatePath(t,e,n,i,a){var r=[],o=n.map(function(t,n){return e[n]+","+t}).join("L");a&&(o=getSplineCurvePointsStr(e,n));var s=[t.path,{d:"M"+o},PATH_ANIM_DUR,STD_EASING];if(r.push(s),t.region){var l=e[0]+","+i+"L",u="L"+e.slice(-1)[0]+", "+i,c=[t.region,{d:"M"+l+o+u},PATH_ANIM_DUR,STD_EASING];r.push(c)}return r}function animatePathStr(t,e){return[t,{d:e},UNIT_ANIM_DUR,STD_EASING]}function _toConsumableArray$1(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e3&&void 0!==arguments[3]?arguments[3]:"linear",a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:void 0,r=arguments.length>5&&void 0!==arguments[5]?arguments[5]:{},o=t.cloneNode(!0),s=t.cloneNode(!0);for(var l in e){var u=void 0;u="transform"===l?document.createElementNS("http://www.w3.org/2000/svg","animateTransform"):document.createElementNS("http://www.w3.org/2000/svg","animate");var c=r[l]||t.getAttribute(l),h=e[l],d={attributeName:l,from:c,to:h,begin:"0s",dur:n/1e3+"s",values:c+";"+h,keySplines:EASING[i],keyTimes:"0;1",calcMode:"spline",fill:"freeze"};a&&(d.type=a);for(var f in d)u.setAttribute(f,d[f]);o.appendChild(u),a?s.setAttribute(l,"translate("+h+")"):s.setAttribute(l,h)}return[o,s]}function transform(t,e){t.style.transform=e,t.style.webkitTransform=e,t.style.msTransform=e,t.style.mozTransform=e,t.style.oTransform=e}function animateSVG(t,e){var n=[],i=[];e.map(function(t){var e=t[0],a=e.parentNode,r=void 0,o=void 0;t[0]=e;var s=animateSVGElement.apply(void 0,_toConsumableArray$1(t)),l=_slicedToArray$1(s,2);r=l[0],o=l[1],n.push(o),i.push([r,a]),a&&a.replaceChild(r,e)});var a=t.cloneNode(!0);return i.map(function(t,i){t[1]&&(t[1].replaceChild(n[i],t[0]),e[i][0]=n[i])}),a}function runSMILAnimation(t,e,n){if(0!==n.length){var i=animateSVG(e,n);e.parentNode==t&&(t.removeChild(e),t.appendChild(i)),setTimeout(function(){i.parentNode==t&&(t.removeChild(i),t.appendChild(e))},REPLACE_ALL_NEW_DUR)}}function downloadFile(t,e){var n=document.createElement("a");n.style="display: none";var i=new Blob(e,{type:"image/svg+xml; charset=utf-8"}),a=window.URL.createObjectURL(i);n.href=a,n.download=t,document.body.appendChild(n),n.click(),setTimeout(function(){document.body.removeChild(n),window.URL.revokeObjectURL(a)},300)}function prepareForExport(t){var e=t.cloneNode(!0);e.classList.add("chart-container"),e.setAttribute("xmlns","http://www.w3.org/2000/svg"),e.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink");var n=$.create("style",{innerHTML:CSSTEXT});e.insertBefore(n,e.firstChild);var i=$.create("div");return i.appendChild(e),i.innerHTML}function _classCallCheck$3(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function _classCallCheck$2(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn$1(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e}function _inherits$1(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)}function treatAsUtc(t){var e=new Date(t);return e.setMinutes(e.getMinutes()-e.getTimezoneOffset()),e}function getYyyyMmDd(t){var e=t.getDate(),n=t.getMonth()+1;return[t.getFullYear(),(n>9?"":"0")+n,(e>9?"":"0")+e].join("-")}function clone(t){return new Date(t.getTime())}function getWeeksBetween(t,e){var n=setDayToSunday(t);return Math.ceil(getDaysBetween(n,e)/NO_OF_DAYS_IN_WEEK)}function getDaysBetween(t,e){var n=SEC_IN_DAY*NO_OF_MILLIS;return(treatAsUtc(e)-treatAsUtc(t))/n}function areInSameMonth(t,e){return t.getMonth()===e.getMonth()&&t.getFullYear()===e.getFullYear()}function getMonthName(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],n=MONTH_NAMES[t];return e?n.slice(0,3):n}function getLastDateInMonth(t,e){return new Date(e,t+1,0)}function setDayToSunday(t){var e=clone(t),n=e.getDay();return 0!==n&&addDays(e,-1*n),e}function addDays(t,e){t.setDate(t.getDate()+e)}function _classCallCheck$5(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function getComponent(t,e,n){var i=Object.keys(componentConfigs).filter(function(e){return t.includes(e)}),a=componentConfigs[i[0]];return Object.assign(a,{constants:e,getData:n}),new ChartComponent(a)}function _toConsumableArray(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e0?1:-1;if(!isFinite(t))return{mantissa:4503599627370496*e,exponent:972};t=Math.abs(t);var n=Math.floor(Math.log10(t));return[e*(t/Math.pow(10,n)),n]}function getChartRangeIntervals(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=Math.ceil(t),i=Math.floor(e),a=n-i,r=a,o=1;a>5&&(a%2!=0&&(a=++n-i),r=a/2,o=2),a<=2&&(o=a/(r=4)),0===a&&(r=5,o=1);for(var s=[],l=0;l<=r;l++)s.push(i+o*l);return s}function getChartIntervals(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=normalize(t),i=_slicedToArray$4(n,2),a=i[0],r=i[1],o=e?e/Math.pow(10,r):0,s=getChartRangeIntervals(a=a.toFixed(6),o);return s=s.map(function(t){return t*Math.pow(10,r)})}function calcChartIntervals(t){function e(t,e){for(var n=getChartIntervals(t),i=n[1]-n[0],a=0,r=1;a1&&void 0!==arguments[1]&&arguments[1],i=Math.max.apply(Math,_toConsumableArray$4(t)),a=Math.min.apply(Math,_toConsumableArray$4(t)),r=[];if(i>=0&&a>=0)normalize(i)[1],r=n?getChartIntervals(i,a):getChartIntervals(i);else if(i>0&&a<0){var o=Math.abs(a);i>=o?(normalize(i)[1],r=e(i,o)):(normalize(o)[1],r=e(o,i).reverse().map(function(t){return-1*t}))}else if(i<=0&&a<=0){var s=Math.abs(a),l=Math.abs(i);normalize(s)[1],r=(r=n?getChartIntervals(s,l):getChartIntervals(s)).reverse().map(function(t){return-1*t})}return r}function getZeroIndex(t){var e=getIntervalSize(t);return t.indexOf(0)>=0?t.indexOf(0):t[0]>0?-1*t[0]/e:-1*t[t.length-1]/e+(t.length-1)}function getIntervalSize(t){return t[1]-t[0]}function getValueRange(t){return t[t.length-1]-t[0]}function scale(t,e){return floatTwo(e.zeroLine-t*e.scaleMultiplier)}function getClosestInArray(t,e){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2],i=e.reduce(function(e,n){return Math.abs(n-t)n?i.slice(0,n):fillArray(i,n-i.length,0),t.values=i}else t.values=a;t.chartType||(AXIS_DATASET_CHART_TYPES.includes(e),t.chartType=e)}),t.yRegions&&t.yRegions.map(function(t){if(t.end1&&void 0!==arguments[1]?arguments[1]:[],n=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],i=t/e.length;i<=0&&(i=1);var a=i/DEFAULT_CHAR_WIDTH,r=void 0;if(n){var o=Math.max.apply(Math,_toConsumableArray$6(e.map(function(t){return t.length})));r=Math.ceil(o/a)}return e.map(function(t,e){return(t+="").length>a&&(n?e%r!=0&&(t=""):t=a-3>0?t.slice(0,a-3)+" ...":t.slice(0,a)+".."),t})}function _toConsumableArray$5(t){if(Array.isArray(t)){for(var e=0,n=Array(t.length);e0&&void 0!==arguments[0]?arguments[0]:"line",e=arguments[1],n=arguments[2];return"axis-mixed"===t?(n.type="line",new AxisChart(e,n)):chartTypes[t]?new chartTypes[t](e,n):void console.error("Undefined chart type: "+t)}var css_248z='.chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ol,.graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}';styleInject(css_248z);var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t};$.create=function(t,e){var n=document.createElement(t);for(var i in e){var a=e[i];if("inside"===i)$(a).appendChild(n);else if("around"===i){var r=$(a);r.parentNode.insertBefore(n,r),n.appendChild(r)}else"styles"===i?"object"===(void 0===a?"undefined":_typeof(a))&&Object.keys(a).map(function(t){n.style[t]=a[t]}):i in n?n[i]=a:n.setAttribute(i,a)}return n};var BASE_MEASURES={margins:{top:10,bottom:10,left:20,right:20},paddings:{top:20,bottom:40,left:30,right:10},baseHeight:240,titleHeight:20,legendHeight:30,titleFontSize:12},INIT_CHART_UPDATE_TIMEOUT=700,CHART_POST_ANIMATE_TIMEOUT=400,DEFAULT_AXIS_CHART_TYPE="line",AXIS_DATASET_CHART_TYPES=["line","bar"],AXIS_LEGEND_BAR_SIZE=100,BAR_CHART_SPACE_RATIO=.5,MIN_BAR_PERCENT_HEIGHT=0,LINE_CHART_DOT_SIZE=4,DOT_OVERLAY_SIZE_INCR=4,PERCENTAGE_BAR_DEFAULT_HEIGHT=20,PERCENTAGE_BAR_DEFAULT_DEPTH=2,HEATMAP_DISTRIBUTION_SIZE=5,HEATMAP_SQUARE_SIZE=10,HEATMAP_GUTTER_SIZE=2,DEFAULT_CHAR_WIDTH=7,TOOLTIP_POINTER_TRIANGLE_HEIGHT=5,DEFAULT_CHART_COLORS=["light-blue","blue","violet","red","orange","yellow","green","light-green","purple","magenta","light-grey","dark-grey"],HEATMAP_COLORS_GREEN=["#ebedf0","#c6e48b","#7bc96f","#239a3b","#196127"],DEFAULT_COLORS={bar:DEFAULT_CHART_COLORS,line:DEFAULT_CHART_COLORS,pie:DEFAULT_CHART_COLORS,percentage:DEFAULT_CHART_COLORS,heatmap:HEATMAP_COLORS_GREEN,donut:DEFAULT_CHART_COLORS},ANGLE_RATIO=Math.PI/180,FULL_ANGLE=360,_createClass$3=function(){function t(t,e){for(var n=0;n\n\t\t\t\t
          \n\t\t\t\t
          '}),this.hideTip(),this.title=this.container.querySelector(".title"),this.dataPointList=this.container.querySelector(".data-point-list"),this.parent.addEventListener("mouseleave",function(){t.hideTip()})}},{key:"fill",value:function(){var t=this,e=void 0;this.index&&this.container.setAttribute("data-point-index",this.index),e=this.titleValueFirst?""+this.titleValue+""+this.titleName:this.titleName+""+this.titleValue+"",this.title.innerHTML=e,this.dataPointList.innerHTML="",this.listValues.map(function(e,n){var i=t.colors[n]||"black",a=0===e.formatted||e.formatted?e.formatted:e.value,r=$.create("li",{styles:{"border-top":"3px solid "+i},innerHTML:''+(0===a||a?a:"")+"\n\t\t\t\t\t"+(e.title?e.title:"")});t.dataPointList.appendChild(r)})}},{key:"calcPosition",value:function(){var t=this.container.offsetWidth;this.top=this.y-this.container.offsetHeight-TOOLTIP_POINTER_TRIANGLE_HEIGHT,this.left=this.x-t/2;var e=this.parent.offsetWidth-t,n=this.container.querySelector(".svg-pointer");if(this.left<0)n.style.left="calc(50% - "+-1*this.left+"px)",this.left=0;else if(this.left>e){var i="calc(50% + "+(this.left-e)+"px)";n.style.left=i,this.left=e}else n.style.left="50%"}},{key:"setValues",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[],a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:-1;this.titleName=n.name,this.titleValue=n.value,this.listValues=i,this.x=t,this.y=e,this.titleValueFirst=n.valueFirst||0,this.index=a,this.refresh()}},{key:"hideTip",value:function(){this.container.style.top="0px",this.container.style.left="0px",this.container.style.opacity="0"}},{key:"showTip",value:function(){this.container.style.top=this.top+"px",this.container.style.left=this.left+"px",this.container.style.opacity="1"}}]),t}(),_typeof$2="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},PRESET_COLOR_MAP={"light-blue":"#7cd6fd",blue:"#5e64ff",violet:"#743ee2",red:"#ff5858",orange:"#ffa00a",yellow:"#feef72",green:"#28a745","light-green":"#98d85b",purple:"#b554ff",magenta:"#ffa3ef",black:"#36114C",grey:"#bdd3e6","light-grey":"#f0f4f7","dark-grey":"#b8c2cc"},getColor=function(t){return/rgb[a]{0,1}\([\d, ]+\)/gim.test(t)?/\D+(\d*)\D+(\d*)\D+(\d*)/gim.exec(t).map(function(t,e){return 0!==e?Number(t).toString(16):"#"}).reduce(function(t,e){return""+t+e}):PRESET_COLOR_MAP[t]||t},_slicedToArray=function(){function t(t,e){var n=[],i=!0,a=!1,r=void 0;try{for(var o,s=t[Symbol.iterator]();!(i=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);i=!0);}catch(t){a=!0,r=t}finally{try{!i&&s.return&&s.return()}finally{if(a)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_typeof$1="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},AXIS_TICK_LENGTH=6,LABEL_MARGIN=4,LABEL_MAX_CHARS=15,FONT_SIZE=10,BASE_LINE_COLOR="#dadada",FONT_FILL="#555b51",makeOverlay={bar:function(t){var e=void 0;"rect"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);var n=t.cloneNode();return n.style.fill="#000000",n.style.opacity="0.4",e&&n.setAttribute("transform",e),n},dot:function(t){var e=void 0;"circle"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);var n=t.cloneNode(),i=t.getAttribute("r"),a=t.getAttribute("fill");return n.setAttribute("r",parseInt(i)+DOT_OVERLAY_SIZE_INCR),n.setAttribute("fill",a),n.style.opacity="0.6",e&&n.setAttribute("transform",e),n},heat_square:function(t){var e=void 0;"circle"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);var n=t.cloneNode(),i=t.getAttribute("r"),a=t.getAttribute("fill");return n.setAttribute("r",parseInt(i)+DOT_OVERLAY_SIZE_INCR),n.setAttribute("fill",a),n.style.opacity="0.6",e&&n.setAttribute("transform",e),n}},updateOverlay={bar:function(t,e){var n=void 0;"rect"!==t.nodeName&&(n=t.getAttribute("transform"),t=t.childNodes[0]);var i=["x","y","width","height"];Object.values(t.attributes).filter(function(t){return i.includes(t.name)&&t.specified}).map(function(t){e.setAttribute(t.name,t.nodeValue)}),n&&e.setAttribute("transform",n)},dot:function(t,e){var n=void 0;"circle"!==t.nodeName&&(n=t.getAttribute("transform"),t=t.childNodes[0]);var i=["cx","cy"];Object.values(t.attributes).filter(function(t){return i.includes(t.name)&&t.specified}).map(function(t){e.setAttribute(t.name,t.nodeValue)}),n&&e.setAttribute("transform",n)},heat_square:function(t,e){var n=void 0;"circle"!==t.nodeName&&(n=t.getAttribute("transform"),t=t.childNodes[0]);var i=["cx","cy"];Object.values(t.attributes).filter(function(t){return i.includes(t.name)&&t.specified}).map(function(t){e.setAttribute(t.name,t.nodeValue)}),n&&e.setAttribute("transform",n)}},_slicedToArray$2=function(){function t(t,e){var n=[],i=!0,a=!1,r=void 0;try{for(var o,s=t[Symbol.iterator]();!(i=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);i=!0);}catch(t){a=!0,r=t}finally{try{!i&&s.return&&s.return()}finally{if(a)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),UNIT_ANIM_DUR=350,PATH_ANIM_DUR=350,MARKER_LINE_ANIM_DUR=UNIT_ANIM_DUR,REPLACE_ALL_NEW_DUR=250,STD_EASING="easein",_slicedToArray$1=function(){function t(t,e){var n=[],i=!0,a=!1,r=void 0;try{for(var o,s=t[Symbol.iterator]();!(i=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);i=!0);}catch(t){a=!0,r=t}finally{try{!i&&s.return&&s.return()}finally{if(a)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),EASING={ease:"0.25 0.1 0.25 1",linear:"0 0 1 1",easein:"0.1 0.8 0.2 1",easeout:"0 0 0.58 1",easeinout:"0.42 0 0.58 1"},CSSTEXT=".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}",_createClass$2=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]&&arguments[0],n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];e&&isHidden(this.parent)||(this.updateWidth(),this.calc(e),this.makeChartArea(),this.setupComponents(),this.components.forEach(function(e){return e.setup(t.drawArea)}),this.render(this.components,!1),n&&(this.data=this.realData,setTimeout(function(){t.update(t.data)},this.initTimeout)),this.renderLegend(),this.setupNavigation(n))}},{key:"calc",value:function(){}},{key:"updateWidth",value:function(){this.baseWidth=getElementContentWidth(this.parent),this.width=this.baseWidth-getExtraWidth(this.measures)}},{key:"makeChartArea",value:function(){this.svg&&this.container.removeChild(this.svg);var t=this.measures;this.svg=makeSVGContainer(this.container,"frappe-chart chart",this.baseWidth,this.baseHeight),this.svgDefs=makeSVGDefs(this.svg),this.title.length&&(this.titleEL=makeText("title",t.margins.left,t.margins.top,this.title,{fontSize:t.titleFontSize,fill:"#666666",dy:t.titleFontSize}));var e=getTopOffset(t);this.drawArea=makeSVGGroup(this.type+"-chart chart-draw-area","translate("+getLeftOffset(t)+", "+e+")"),this.config.showLegend&&(e+=this.height+t.paddings.bottom,this.legendArea=makeSVGGroup("chart-legend","translate("+getLeftOffset(t)+", "+e+")")),this.title.length&&this.svg.appendChild(this.titleEL),this.svg.appendChild(this.drawArea),this.config.showLegend&&this.svg.appendChild(this.legendArea),this.updateTipOffset(getLeftOffset(t),getTopOffset(t))}},{key:"updateTipOffset",value:function(t,e){this.tip.offset={x:t,y:e}}},{key:"setupComponents",value:function(){this.components=new Map}},{key:"update",value:function(t){t||console.error("No data to update."),this.data=this.prepareData(t),this.calc(),this.render(this.components,this.config.animate),this.renderLegend()}},{key:"render",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.components,n=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.config.isNavigable&&this.overlays.map(function(t){return t.parentNode.removeChild(t)});var i=[];e.forEach(function(t){i=i.concat(t.update(n))}),i.length>0?(runSMILAnimation(this.container,this.svg,i),setTimeout(function(){e.forEach(function(t){return t.make()}),t.updateNav()},CHART_POST_ANIMATE_TIMEOUT)):(e.forEach(function(t){return t.make()}),this.updateNav())}},{key:"updateNav",value:function(){this.config.isNavigable&&(this.makeOverlay(),this.bindUnits())}},{key:"renderLegend",value:function(){}},{key:"setupNavigation",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.config.isNavigable&&e&&(this.bindOverlay(),this.keyActions={13:this.onEnterKey.bind(this),37:this.onLeftArrow.bind(this),38:this.onUpArrow.bind(this),39:this.onRightArrow.bind(this),40:this.onDownArrow.bind(this)},document.addEventListener("keydown",function(e){isElementInViewport(t.container)&&(e=e||window.event,t.keyActions[e.keyCode]&&t.keyActions[e.keyCode]())}))}},{key:"makeOverlay",value:function(){}},{key:"updateOverlay",value:function(){}},{key:"bindOverlay",value:function(){}},{key:"bindUnits",value:function(){}},{key:"onLeftArrow",value:function(){}},{key:"onRightArrow",value:function(){}},{key:"onUpArrow",value:function(){}},{key:"onDownArrow",value:function(){}},{key:"onEnterKey",value:function(){}},{key:"addDataPoint",value:function(){}},{key:"removeDataPoint",value:function(){}},{key:"getDataPoint",value:function(){}},{key:"setCurrentDataPoint",value:function(){}},{key:"updateDataset",value:function(){}},{key:"export",value:function(){var t=prepareForExport(this.svg);downloadFile(this.title||"Chart",[t])}}]),t}(),_createClass$1=function(){function t(t,e){for(var n=0;n=0}),a=i;if(i.length>n){i.sort(function(t,e){return e[0]-t[0]}),a=i.slice(0,n-1);var r=0;i.slice(n-1).map(function(t){r+=t[0]}),a.push([r,"Rest"]),this.colors[n-1]="grey"}e.labels=[],a.map(function(t){e.sliceTotals.push(round(t[0])),e.labels.push(t[1])}),e.grandTotal=e.sliceTotals.reduce(function(t,e){return t+e},0),this.center={x:this.width/2,y:this.height/2}}},{key:"renderLegend",value:function(){var t=this,e=this.state;this.legendArea.textContent="",this.legendTotals=e.sliceTotals.slice(0,this.config.maxLegendPoints);var n=0,i=0;this.legendTotals.map(function(a,r){var o=150,s=Math.floor((t.width-getExtraWidth(t.measures))/o);t.legendTotals.lengths&&(n=0,i+=20);var l=o*n+5,u=t.config.truncateLegends?truncateString(e.labels[r],o/10):e.labels[r],c=t.config.formatTooltipY?t.config.formatTooltipY(a):a,h=legendDot(l,i,5,t.colors[r],u+": "+c,!1);t.legendArea.appendChild(h),n++})}}]),e}(BaseChart),NO_OF_YEAR_MONTHS=12,NO_OF_DAYS_IN_WEEK=7,NO_OF_MILLIS=1e3,SEC_IN_DAY=86400,MONTH_NAMES=["January","February","March","April","May","June","July","August","September","October","November","December"],DAY_NAMES_SHORT=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],_slicedToArray$3=function(){function t(t,e){var n=[],i=!0,a=!1,r=void 0;try{for(var o,s=t[Symbol.iterator]();!(i=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);i=!0);}catch(t){a=!0,r=t}finally{try{!i&&s.return&&s.return()}finally{if(a)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_createClass$4=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0])||arguments[0];this.refresh();var e=[];return t&&(e=this.animateElements(this.data)||[]),e}}]),t}(),componentConfigs={donutSlices:{layerClass:"donut-slices",makeElements:function(t){return t.sliceStrings.map(function(e,n){var i=makePath(e,"donut-path",t.colors[n],"none",t.strokeWidth);return i.style.transition="transform .3s;",i})},animateElements:function(t){return this.store.map(function(e,n){return animatePathStr(e,t.sliceStrings[n])})}},pieSlices:{layerClass:"pie-slices",makeElements:function(t){return t.sliceStrings.map(function(e,n){var i=makePath(e,"pie-path","none",t.colors[n]);return i.style.transition="transform .3s;",i})},animateElements:function(t){return this.store.map(function(e,n){return animatePathStr(e,t.sliceStrings[n])})}},percentageBars:{layerClass:"percentage-bars",makeElements:function(t){var e=this;return t.xPositions.map(function(n,i){return percentageBar(n,0,t.widths[i],e.constants.barHeight,e.constants.barDepth,t.colors[i])})},animateElements:function(t){if(t)return[]}},yAxis:{layerClass:"y axis",makeElements:function(t){var e=this;return t.positions.map(function(n,i){return yLine(n,t.labels[i],e.constants.width,{mode:e.constants.mode,pos:e.constants.pos,shortenNumbers:e.constants.shortenNumbers})})},animateElements:function(t){var e=t.positions,n=t.labels,i=this.oldData.positions,a=this.oldData.labels,r=equilizeNoOfElements(i,e),o=_slicedToArray$3(r,2);i=o[0],e=o[1];var s=equilizeNoOfElements(a,n),l=_slicedToArray$3(s,2);return a=l[0],n=l[1],this.render({positions:i,labels:n}),this.store.map(function(t,n){return translateHoriLine(t,e[n],i[n])})}},xAxis:{layerClass:"x axis",makeElements:function(t){var e=this;return t.positions.map(function(n,i){return xLine(n,t.calcLabels[i],e.constants.height,{mode:e.constants.mode,pos:e.constants.pos})})},animateElements:function(t){var e=t.positions,n=t.calcLabels,i=this.oldData.positions,a=this.oldData.calcLabels,r=equilizeNoOfElements(i,e),o=_slicedToArray$3(r,2);i=o[0],e=o[1];var s=equilizeNoOfElements(a,n),l=_slicedToArray$3(s,2);return a=l[0],n=l[1],this.render({positions:i,calcLabels:n}),this.store.map(function(t,n){return translateVertLine(t,e[n],i[n])})}},yMarkers:{layerClass:"y-markers",makeElements:function(t){var e=this;return t.map(function(t){return yMarker(t.position,t.label,e.constants.width,{labelPos:t.options.labelPos,mode:"span",lineType:"dashed"})})},animateElements:function(t){var e=equilizeNoOfElements(this.oldData,t),n=_slicedToArray$3(e,2);this.oldData=n[0];var i=(t=n[1]).map(function(t){return t.position}),a=t.map(function(t){return t.label}),r=t.map(function(t){return t.options}),o=this.oldData.map(function(t){return t.position});return this.render(o.map(function(t,e){return{position:o[e],label:a[e],options:r[e]}})),this.store.map(function(t,e){return translateHoriLine(t,i[e],o[e])})}},yRegions:{layerClass:"y-regions",makeElements:function(t){var e=this;return t.map(function(t){return yRegion(t.startPos,t.endPos,e.constants.width,t.label,{labelPos:t.options.labelPos})})},animateElements:function(t){var e=equilizeNoOfElements(this.oldData,t),n=_slicedToArray$3(e,2);this.oldData=n[0];var i=(t=n[1]).map(function(t){return t.endPos}),a=t.map(function(t){return t.label}),r=t.map(function(t){return t.startPos}),o=t.map(function(t){return t.options}),s=this.oldData.map(function(t){return t.endPos}),l=this.oldData.map(function(t){return t.startPos});this.render(s.map(function(t,e){return{startPos:l[e],endPos:s[e],label:a[e],options:o[e]}}));var u=[];return this.store.map(function(t,e){u=u.concat(animateRegion(t,r[e],i[e],s[e]))}),u}},heatDomain:{layerClass:function(){return"heat-domain domain-"+this.constants.index},makeElements:function(t){var e=this,n=this.constants,i=n.index,a=n.colWidth,r=n.rowHeight,o=n.squareSize,s=n.radius,l=n.xTranslate,u=0;return this.serializedSubDomains=[],t.cols.map(function(t,n){1===n&&e.labels.push(makeText("domain-name",l,-12,getMonthName(i,!0).toUpperCase(),{fontSize:9})),t.map(function(t,n){if(t.fill){var i={"data-date":t.yyyyMmDd,"data-value":t.dataValue,"data-day":n},a=heatSquare("day",l,u,o,s,t.fill,i);e.serializedSubDomains.push(a)}u+=r}),u=0,l+=a}),this.serializedSubDomains},animateElements:function(t){if(t)return[]}},barGraph:{layerClass:function(){return"dataset-units dataset-bars dataset-"+this.constants.index},makeElements:function(t){var e=this.constants;return this.unitType="bar",this.units=t.yPositions.map(function(n,i){return datasetBar(t.xPositions[i],n,t.barWidth,e.color,t.labels[i],i,t.offsets[i],{zeroLine:t.zeroLine,barsWidth:t.barsWidth,minHeight:e.minHeight})}),this.units},animateElements:function(t){var e=t.xPositions,n=t.yPositions,i=t.offsets,a=t.labels,r=this.oldData.xPositions,o=this.oldData.yPositions,s=this.oldData.offsets,l=this.oldData.labels,u=equilizeNoOfElements(r,e),c=_slicedToArray$3(u,2);r=c[0],e=c[1];var h=equilizeNoOfElements(o,n),d=_slicedToArray$3(h,2);o=d[0],n=d[1];var f=equilizeNoOfElements(s,i),p=_slicedToArray$3(f,2);s=p[0],i=p[1];var v=equilizeNoOfElements(l,a),g=_slicedToArray$3(v,2);l=g[0],a=g[1],this.render({xPositions:r,yPositions:o,offsets:s,labels:a,zeroLine:this.oldData.zeroLine,barsWidth:this.oldData.barsWidth,barWidth:this.oldData.barWidth});var y=[];return this.store.map(function(a,r){y=y.concat(animateBar(a,e[r],n[r],t.barWidth,i[r],{zeroLine:t.zeroLine}))}),y}},lineGraph:{layerClass:function(){return"dataset-units dataset-line dataset-"+this.constants.index},makeElements:function(t){var e=this.constants;return this.unitType="dot",this.paths={},e.hideLine||(this.paths=getPaths(t.xPositions,t.yPositions,e.color,{heatline:e.heatline,regionFill:e.regionFill,spline:e.spline},{svgDefs:e.svgDefs,zeroLine:t.zeroLine})),this.units=[],e.hideDots||(this.units=t.yPositions.map(function(n,i){return datasetDot(t.xPositions[i],n,t.radius,e.color,e.valuesOverPoints?t.values[i]:"",i)})),Object.values(this.paths).concat(this.units)},animateElements:function(t){var e=t.xPositions,n=t.yPositions,i=t.values,a=this.oldData.xPositions,r=this.oldData.yPositions,o=this.oldData.values,s=equilizeNoOfElements(a,e),l=_slicedToArray$3(s,2);a=l[0],e=l[1];var u=equilizeNoOfElements(r,n),c=_slicedToArray$3(u,2);r=c[0],n=c[1];var h=equilizeNoOfElements(o,i),d=_slicedToArray$3(h,2);o=d[0],i=d[1],this.render({xPositions:a,yPositions:r,values:i,zeroLine:this.oldData.zeroLine,radius:this.oldData.radius});var f=[];return Object.keys(this.paths).length&&(f=f.concat(animatePath(this.paths,e,n,t.zeroLine,this.constants.spline))),this.units.length&&this.units.map(function(t,i){f=f.concat(animateDot(t,e[i],n[i]))}),f}}},_createClass=function(){function t(t,e){for(var n=0;n0?t.formattedLabels[r]:t.state.labels[r])+": ",h=e.sliceTotals[r]/e.grandTotal;t.tip.setValues(l,u,{name:c,value:(100*h).toFixed(1)+"%"}),t.tip.showTip()}})}}]),e}(AggregationChart),_createClass$5=function(){function t(t,e){for(var n=0;nthis.width?this.center.x:this.center.y;var i=this.radius,a=this.clockWise,r=n.slicesProperties||[];n.sliceStrings=[],n.slicesProperties=[];var o=180-this.config.startAngle;n.sliceTotals.map(function(e,s){var l=o,u=e/n.grandTotal*FULL_ANGLE,c=u>180?1:0,h=a?-u:u,d=o+=h,f=getPositionByAngle(l,i),p=getPositionByAngle(d,i),v=t.init&&r[s],g=void 0,y=void 0;t.init?(g=v?v.startPosition:f,y=v?v.endPosition:f):(g=f,y=p);var m=360===u?makeCircleStr(g,y,t.center,t.radius,a,c):makeArcPathStr(g,y,t.center,t.radius,a,c);n.sliceStrings.push(m),n.slicesProperties.push({startPosition:f,endPosition:p,value:e,total:n.grandTotal,startAngle:l,endAngle:d,angle:h})}),this.init=0}},{key:"setupComponents",value:function(){var t=this.state,e=[["pieSlices",{},function(){return{sliceStrings:t.sliceStrings,colors:this.colors}}.bind(this)]];this.components=new Map(e.map(function(t){var e=getComponent.apply(void 0,_toConsumableArray$2(t));return[t[0],e]}))}},{key:"calTranslateByAngle",value:function(t){var e=this.radius,n=this.hoverRadio,i=getPositionByAngle(t.startAngle+t.angle/2,e);return"translate3d("+i.x*n+"px,"+i.y*n+"px,0)"}},{key:"hoverSlice",value:function(t,e,n,i){if(t){var a=this.colors[e];if(n){transform(t,this.calTranslateByAngle(this.state.slicesProperties[e])),t.style.fill=lightenDarkenColor(a,50);var r=getOffset(this.svg),o=i.pageX-r.left+10,s=i.pageY-r.top-10,l=(this.formatted_labels&&this.formatted_labels.length>0?this.formatted_labels[e]:this.state.labels[e])+": ",u=(100*this.state.sliceTotals[e]/this.state.grandTotal).toFixed(1);this.tip.setValues(o,s,{name:l,value:u+"%"}),this.tip.showTip()}else transform(t,"translate3d(0,0,0)"),this.tip.hideTip(),t.style.fill=a}}},{key:"bindTooltip",value:function(){this.container.addEventListener("mousemove",this.mouseMove),this.container.addEventListener("mouseleave",this.mouseLeave)}},{key:"mouseMove",value:function(t){var e=t.target,n=this.components.get("pieSlices").store,i=this.curActiveSliceIndex,a=this.curActiveSlice;if(n.includes(e)){var r=n.indexOf(e);this.hoverSlice(a,i,!1),this.curActiveSlice=e,this.curActiveSliceIndex=r,this.hoverSlice(e,r,!0,t)}else this.mouseLeave()}},{key:"mouseLeave",value:function(){this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,!1)}}]),e}(AggregationChart),_slicedToArray$4=function(){function t(t,e){var n=[],i=!0,a=!1,r=void 0;try{for(var o,s=t[Symbol.iterator]();!(i=(o=s.next()).done)&&(n.push(o.value),!e||n.length!==e);i=!0);}catch(t){a=!0,r=t}finally{try{!i&&s.return&&s.return()}finally{if(a)throw r}}return n}return function(e,n){if(Array.isArray(e))return e;if(Symbol.iterator in Object(e))return t(e,n);throw new TypeError("Invalid attempt to destructure non-iterable instance")}}(),_createClass$6=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:this.data;if(t.start&&t.end&&t.start>t.end)throw new Error("Start date cannot be greater than end date.");if(t.start||(t.start=new Date,t.start.setFullYear(t.start.getFullYear()-1)),t.end||(t.end=new Date),t.dataPoints=t.dataPoints||{},parseInt(Object.keys(t.dataPoints)[0])>1e5){var e={};Object.keys(t.dataPoints).forEach(function(n){var i=new Date(n*NO_OF_MILLIS);e[getYyyyMmDd(i)]=t.dataPoints[n]}),t.dataPoints=e}return t}},{key:"calc",value:function(){var t=this.state;t.start=clone(this.data.start),t.end=clone(this.data.end),t.firstWeekStart=clone(t.start),t.noOfWeeks=getWeeksBetween(t.start,t.end),t.distribution=calcDistribution(Object.values(this.data.dataPoints),HEATMAP_DISTRIBUTION_SIZE),t.domainConfigs=this.getDomains()}},{key:"setupComponents",value:function(){var t=this,e=this.state,n=this.discreteDomains?0:1,i=e.domainConfigs.map(function(i,a){return["heatDomain",{index:i.index,colWidth:COL_WIDTH,rowHeight:ROW_HEIGHT,squareSize:HEATMAP_SQUARE_SIZE,radius:t.rawChartArgs.radius||0,xTranslate:e.domainConfigs.filter(function(t,e){return e1&&void 0!==arguments[1]?arguments[1]:"",n=[t.getMonth(),t.getFullYear()],i=n[0],a=n[1],r=setDayToSunday(t),o={index:i,cols:[]};addDays(e=clone(e)||getLastDateInMonth(i,a),1);for(var s=getWeeksBetween(r,e),l=[],u=void 0,c=0;c2&&void 0!==arguments[2]&&arguments[2],i=this.state,a=clone(t),r=[],o=0;o=i.start&&a<=i.end;n||a.getMonth()!==e||!l?s.yyyyMmDd=getYyyyMmDd(a):s=this.getSubDomainConfig(a),r.push(s)}return r}},{key:"getSubDomainConfig",value:function(t){var e=getYyyyMmDd(t),n=this.data.dataPoints[e];return{yyyyMmDd:e,dataValue:n||0,fill:this.colors[getMaxCheckpoint(n,this.state.distribution)]}}}]),e}(BaseChart),_createClass$7=function(){function t(t,e){for(var n=0;n0&&void 0!==arguments[0]?arguments[0]:this.data,this.type)}},{key:"prepareFirstData",value:function(){return zeroDataPrep(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.data)}},{key:"calc",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.calcXPositions(),t||this.calcYAxisParameters(this.getAllYValues(),"line"===this.type),this.makeDataByIndex()}},{key:"calcXPositions",value:function(){var t=this.state,e=this.data.labels;t.datasetLength=e.length,t.unitWidth=this.width/t.datasetLength,t.xOffset=t.unitWidth/2,t.xAxis={labels:e,positions:e.map(function(e,n){return floatTwo(t.xOffset+n*t.unitWidth)})}}},{key:"calcYAxisParameters",value:function(t){var e=calcChartIntervals(t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:"false"),n=this.height/getValueRange(e),i=getIntervalSize(e)*n,a=this.height-getZeroIndex(e)*i;this.state.yAxis={labels:e,positions:e.map(function(t){return a-t*n}),scaleMultiplier:n,zeroLine:a},this.calcDatasetPoints(),this.calcYExtremes(),this.calcYRegions()}},{key:"calcDatasetPoints",value:function(){var t=this.state,e=function(e){return e.map(function(e){return scale(e,t.yAxis)})};t.datasets=this.data.datasets.map(function(t,n){var i=t.values,a=t.cumulativeYs||[];return{name:t.name&&t.name.replace(/<|>|&/g,function(t){return"&"==t?"&":"<"==t?"<":">"}),index:n,chartType:t.chartType,values:i,yPositions:e(i),cumulativeYs:a,cumulativeYPos:e(a)}})}},{key:"calcYExtremes",value:function(){var t=this.state;if(this.barOptions.stacked)return void(t.yExtremes=t.datasets[t.datasets.length-1].cumulativeYPos);t.yExtremes=new Array(t.datasetLength).fill(9999),t.datasets.map(function(e){e.yPositions.map(function(e,n){egetTopOffset(n)?t.mapTooltipXPosition(a):t.tip.hideTip()})}},{key:"mapTooltipXPosition",value:function(t){var e=this.state;if(e.yExtremes){var n=getClosestInArray(t,e.xAxis.positions,!0);if(n>=0){var i=this.dataByIndex[n];this.tip.setValues(i.xPos+this.tip.offset.x,i.yExtreme+this.tip.offset.y,{name:i.formattedLabel,value:""},i.values,n),this.tip.showTip()}}}},{key:"renderLegend",value:function(){var t=this,e=this.data;e.datasets.length>1&&(this.legendArea.textContent="",e.datasets.map(function(e,n){var i=AXIS_LEGEND_BAR_SIZE,a=legendBar(i*n,"0",i,t.colors[n],e.name,t.config.truncateLegends);t.legendArea.appendChild(a)}))}},{key:"makeOverlay",value:function(){var t=this;if(this.init)return void(this.init=0);this.overlayGuides&&this.overlayGuides.forEach(function(t){var e=t.overlay;e.parentNode.removeChild(e)}),this.overlayGuides=this.dataUnitComponents.map(function(t){return{type:t.unitType,overlay:void 0,units:t.units}}),void 0===this.state.currentIndex&&(this.state.currentIndex=this.state.datasetLength-1),this.overlayGuides.map(function(e){var n=e.units[t.state.currentIndex];e.overlay=makeOverlay[e.type](n),t.drawArea.appendChild(e.overlay)})}},{key:"updateOverlayGuides",value:function(){this.overlayGuides&&this.overlayGuides.forEach(function(t){var e=t.overlay;e.parentNode.removeChild(e)})}},{key:"bindOverlay",value:function(){var t=this;this.parent.addEventListener("data-select",function(){t.updateOverlay()})}},{key:"bindUnits",value:function(){var t=this;this.dataUnitComponents.map(function(e){e.units.map(function(e){e.addEventListener("click",function(){var n=e.getAttribute("data-point-index");t.setCurrentDataPoint(n)})})}),this.tip.container.addEventListener("click",function(){var e=t.tip.container.getAttribute("data-point-index");t.setCurrentDataPoint(e)})}},{key:"updateOverlay",value:function(){var t=this;this.overlayGuides.map(function(e){var n=e.units[t.state.currentIndex];updateOverlay[e.type](n,e.overlay)})}},{key:"onLeftArrow",value:function(){this.setCurrentDataPoint(this.state.currentIndex-1)}},{key:"onRightArrow",value:function(){this.setCurrentDataPoint(this.state.currentIndex+1)}},{key:"getDataPoint",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.state.currentIndex,e=this.state;return{index:t,label:e.xAxis.labels[t],values:e.datasets.map(function(e){return e.values[t]})}}},{key:"setCurrentDataPoint",value:function(t){var e=this.state;(t=parseInt(t))<0&&(t=0),t>=e.xAxis.labels.length&&(t=e.xAxis.labels.length-1),t!==e.currentIndex&&(e.currentIndex=t,fire(this.parent,"data-select",this.getDataPoint()))}},{key:"addDataPoint",value:function(t,n){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.state.datasetLength;_get$3(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"addDataPoint",this).call(this,t,n,i),this.data.labels.splice(i,0,t),this.data.datasets.map(function(t,e){t.values.splice(i,0,n[e])}),this.update(this.data)}},{key:"removeDataPoint",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.state.datasetLength-1;this.data.labels.length<=1||(_get$3(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"removeDataPoint",this).call(this,t),this.data.labels.splice(t,1),this.data.datasets.map(function(e){e.values.splice(t,1)}),this.update(this.data))}},{key:"updateDataset",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;this.data.datasets[e].values=t,this.update(this.data)}},{key:"updateDatasets",value:function(t){this.data.datasets.map(function(e,n){t[n]&&(e.values=t[n])}),this.update(this.data)}}]),e}(BaseChart),_createClass$8=function(){function t(t,e){for(var n=0;nthis.width?this.center.x-this.strokeWidth/2:this.center.y-this.strokeWidth/2;var i=this.radius,a=this.clockWise,r=n.slicesProperties||[];n.sliceStrings=[],n.slicesProperties=[];var o=180-this.config.startAngle;n.sliceTotals.map(function(e,s){var l=o,u=e/n.grandTotal*FULL_ANGLE,c=u>180?1:0,h=a?-u:u,d=o+=h,f=getPositionByAngle(l,i),p=getPositionByAngle(d,i),v=t.init&&r[s],g=void 0,y=void 0;t.init?(g=v?v.startPosition:f,y=v?v.endPosition:f):(g=f,y=p);var m=360===u?makeStrokeCircleStr(g,y,t.center,t.radius,t.clockWise,c):makeArcStrokePathStr(g,y,t.center,t.radius,t.clockWise,c);n.sliceStrings.push(m),n.slicesProperties.push({startPosition:f,endPosition:p,value:e,total:n.grandTotal,startAngle:l,endAngle:d,angle:h})}),this.init=0}},{key:"setupComponents",value:function(){var t=this.state,e=[["donutSlices",{},function(){return{sliceStrings:t.sliceStrings,colors:this.colors,strokeWidth:this.strokeWidth}}.bind(this)]];this.components=new Map(e.map(function(t){var e=getComponent.apply(void 0,_toConsumableArray$7(t));return[t[0],e]}))}},{key:"calTranslateByAngle",value:function(t){var e=this.radius,n=this.hoverRadio,i=getPositionByAngle(t.startAngle+t.angle/2,e);return"translate3d("+i.x*n+"px,"+i.y*n+"px,0)"}},{key:"hoverSlice",value:function(t,e,n,i){if(t){var a=this.colors[e];if(n){transform(t,this.calTranslateByAngle(this.state.slicesProperties[e])),t.style.stroke=lightenDarkenColor(a,50);var r=getOffset(this.svg),o=i.pageX-r.left+10,s=i.pageY-r.top-10,l=(this.formatted_labels&&this.formatted_labels.length>0?this.formatted_labels[e]:this.state.labels[e])+": ",u=(100*this.state.sliceTotals[e]/this.state.grandTotal).toFixed(1);this.tip.setValues(o,s,{name:l,value:u+"%"}),this.tip.showTip()}else transform(t,"translate3d(0,0,0)"),this.tip.hideTip(),t.style.stroke=a}}},{key:"bindTooltip",value:function(){this.container.addEventListener("mousemove",this.mouseMove),this.container.addEventListener("mouseleave",this.mouseLeave)}},{key:"mouseMove",value:function(t){var e=t.target,n=this.components.get("donutSlices").store,i=this.curActiveSliceIndex,a=this.curActiveSlice;if(n.includes(e)){var r=n.indexOf(e);this.hoverSlice(a,i,!1),this.curActiveSlice=e,this.curActiveSliceIndex=r,this.hoverSlice(e,r,!0,t)}else this.mouseLeave()}},{key:"mouseLeave",value:function(){this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,!1)}}]),e}(AggregationChart),chartTypes={bar:AxisChart,line:AxisChart,percentage:PercentageChart,heatmap:Heatmap,pie:PieChart,donut:DonutChart},Chart=function t(e,n){return _classCallCheck(this,t),getChartByType(n.type,e,n)};export{Chart,PercentageChart,PieChart,Heatmap,AxisChart}; -//# sourceMappingURL=frappe-charts.min.esm.js.map diff --git a/node_modules/frappe-charts/dist/frappe-charts.min.esm.js.map b/node_modules/frappe-charts/dist/frappe-charts.min.esm.js.map deleted file mode 100644 index 066b0fa..0000000 --- a/node_modules/frappe-charts/dist/frappe-charts.min.esm.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"frappe-charts.min.esm.js","sources":["../node_modules/style-inject/dist/style-inject.es.js","../src/js/utils/dom.js","../src/js/utils/constants.js","../src/js/utils/helpers.js","../src/js/utils/draw-utils.js","../src/js/utils/colors.js","../src/js/utils/draw.js","../src/js/utils/animate.js","../src/js/utils/animation.js","../src/js/utils/export.js","../src/js/utils/date-utils.js","../src/js/objects/ChartComponents.js","../src/js/utils/intervals.js","../src/js/utils/axis-chart-utils.js","../src/js/chart.js","../src/js/objects/SvgTip.js","../src/css/chartsCss.js","../src/js/charts/BaseChart.js","../src/js/charts/AggregationChart.js","../src/js/charts/PercentageChart.js","../src/js/charts/PieChart.js","../src/js/charts/Heatmap.js","../src/js/charts/AxisChart.js","../src/js/charts/DonutChart.js"],"sourcesContent":["function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","export function $(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\nexport function findNodeIndex(node)\n{\n\tvar i = 0;\n\twhile (node.previousSibling) {\n\t\tnode = node.previousSibling;\n\t\ti++;\n\t}\n\treturn i;\n}\n\n$.create = (tag, o) => {\n\tvar element = document.createElement(tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (i in element ) {\n\t\t\telement[i] = val;\n\t\t}\n\t\telse {\n\t\t\telement.setAttribute(i, val);\n\t\t}\n\t}\n\n\treturn element;\n};\n\nexport function getOffset(element) {\n\tlet rect = element.getBoundingClientRect();\n\treturn {\n\t\t// https://stackoverflow.com/a/7436602/6495043\n\t\t// rect.top varies with scroll, so we add whatever has been\n\t\t// scrolled to it to get absolute distance from actual page top\n\t\ttop: rect.top + (document.documentElement.scrollTop || document.body.scrollTop),\n\t\tleft: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft)\n\t};\n}\n\n// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent\n// an element's offsetParent property will return null whenever it, or any of its parents,\n// is hidden via the display style property.\nexport function isHidden(el) {\n\treturn (el.offsetParent === null);\n}\n\nexport function isElementInViewport(el) {\n\t// Although straightforward: https://stackoverflow.com/a/7557433/6495043\n\tvar rect = el.getBoundingClientRect();\n\n\treturn (\n\t\trect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */\n rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */\n\t);\n}\n\nexport function getElementContentWidth(element) {\n\tvar styles = window.getComputedStyle(element);\n\tvar padding = parseFloat(styles.paddingLeft) +\n\t\tparseFloat(styles.paddingRight);\n\n\treturn element.clientWidth - padding;\n}\n\nexport function bind(element, o){\n\tif (element) {\n\t\tfor (var event in o) {\n\t\t\tvar callback = o[event];\n\n\t\t\tevent.split(/\\s+/).forEach(function (event) {\n\t\t\t\telement.addEventListener(event, callback);\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport function unbind(element, o){\n\tif (element) {\n\t\tfor (var event in o) {\n\t\t\tvar callback = o[event];\n\n\t\t\tevent.split(/\\s+/).forEach(function(event) {\n\t\t\t\telement.removeEventListener(event, callback);\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport function fire(target, type, properties) {\n\tvar evt = document.createEvent(\"HTMLEvents\");\n\n\tevt.initEvent(type, true, true );\n\n\tfor (var j in properties) {\n\t\tevt[j] = properties[j];\n\t}\n\n\treturn target.dispatchEvent(evt);\n}\n\n// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/\nexport function forEachNode(nodeList, callback, scope) {\n\tif(!nodeList) return;\n\tfor (var i = 0; i < nodeList.length; i++) {\n\t\tcallback.call(scope, nodeList[i], i);\n\t}\n}\n\nexport function activate($parent, $child, commonClass, activeClass='active', index = -1) {\n\tlet $children = $parent.querySelectorAll(`.${commonClass}.${activeClass}`);\n\n\tforEachNode($children, (node, i) => {\n\t\tif(index >= 0 && i <= index) return;\n\t\tnode.classList.remove(activeClass);\n\t});\n\n\t$child.classList.add(activeClass);\n}\n","export const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];\n\nexport const COMPATIBLE_CHARTS = {\n\tbar: ['line', 'scatter', 'percentage', 'pie'],\n\tline: ['scatter', 'bar', 'percentage', 'pie'],\n\tpie: ['line', 'scatter', 'percentage', 'bar'],\n\tpercentage: ['bar', 'line', 'scatter', 'pie'],\n\theatmap: []\n};\n\nexport const DATA_COLOR_DIVISIONS = {\n\tbar: 'datasets',\n\tline: 'datasets',\n\tpie: 'labels',\n\tpercentage: 'labels',\n\theatmap: HEATMAP_DISTRIBUTION_SIZE\n};\n\nexport const BASE_MEASURES = {\n\tmargins: {\n\t\ttop: 10,\n\t\tbottom: 10,\n\t\tleft: 20,\n\t\tright: 20\n\t},\n\tpaddings: {\n\t\ttop: 20,\n\t\tbottom: 40,\n\t\tleft: 30,\n\t\tright: 10\n\t},\n\n\tbaseHeight: 240,\n\ttitleHeight: 20,\n\tlegendHeight: 30,\n\n\ttitleFontSize: 12,\n};\n\nexport function getTopOffset(m) {\n\treturn m.titleHeight + m.margins.top + m.paddings.top;\n}\n\nexport function getLeftOffset(m) {\n\treturn m.margins.left + m.paddings.left;\n}\n\nexport function getExtraHeight(m) {\n\tlet totalExtraHeight = m.margins.top + m.margins.bottom\n\t\t+ m.paddings.top + m.paddings.bottom\n\t\t+ m.titleHeight + m.legendHeight;\n\treturn totalExtraHeight;\n}\n\nexport function getExtraWidth(m) {\n\tlet totalExtraWidth = m.margins.left + m.margins.right\n\t\t+ m.paddings.left + m.paddings.right;\n\n\treturn totalExtraWidth;\n}\n\nexport const INIT_CHART_UPDATE_TIMEOUT = 700;\nexport const CHART_POST_ANIMATE_TIMEOUT = 400;\n\nexport const DEFAULT_AXIS_CHART_TYPE = 'line';\nexport const AXIS_DATASET_CHART_TYPES = ['line', 'bar'];\n\nexport const AXIS_LEGEND_BAR_SIZE = 100;\n\nexport const BAR_CHART_SPACE_RATIO = 0.5;\nexport const MIN_BAR_PERCENT_HEIGHT = 0.00;\n\nexport const LINE_CHART_DOT_SIZE = 4;\nexport const DOT_OVERLAY_SIZE_INCR = 4;\n\nexport const PERCENTAGE_BAR_DEFAULT_HEIGHT = 20;\nexport const PERCENTAGE_BAR_DEFAULT_DEPTH = 2;\n\n// Fixed 5-color theme,\n// More colors are difficult to parse visually\nexport const HEATMAP_DISTRIBUTION_SIZE = 5;\n\nexport const HEATMAP_SQUARE_SIZE = 10;\nexport const HEATMAP_GUTTER_SIZE = 2;\n\nexport const DEFAULT_CHAR_WIDTH = 7;\n\nexport const TOOLTIP_POINTER_TRIANGLE_HEIGHT = 5;\n\nconst DEFAULT_CHART_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',\n\t'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey'];\nconst HEATMAP_COLORS_GREEN = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];\nexport const HEATMAP_COLORS_BLUE = ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'];\nexport const HEATMAP_COLORS_YELLOW = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];\n\nexport const DEFAULT_COLORS = {\n\tbar: DEFAULT_CHART_COLORS,\n\tline: DEFAULT_CHART_COLORS,\n\tpie: DEFAULT_CHART_COLORS,\n\tpercentage: DEFAULT_CHART_COLORS,\n\theatmap: HEATMAP_COLORS_GREEN,\n\tdonut: DEFAULT_CHART_COLORS\n};\n\n// Universal constants\nexport const ANGLE_RATIO = Math.PI / 180;\nexport const FULL_ANGLE = 360;\n","import { ANGLE_RATIO } from './constants';\n\n/**\n * Returns the value of a number upto 2 decimal places.\n * @param {Number} d Any number\n */\nexport function floatTwo(d) {\n\treturn parseFloat(d.toFixed(2));\n}\n\n/**\n * Returns whether or not two given arrays are equal.\n * @param {Array} arr1 First array\n * @param {Array} arr2 Second array\n */\nexport function arraysEqual(arr1, arr2) {\n\tif(arr1.length !== arr2.length) return false;\n\tlet areEqual = true;\n\tarr1.map((d, i) => {\n\t\tif(arr2[i] !== d) areEqual = false;\n\t});\n\treturn areEqual;\n}\n\n/**\n * Shuffles array in place. ES6 version\n * @param {Array} array An array containing the items.\n */\nexport function shuffle(array) {\n\t// Awesomeness: https://bost.ocks.org/mike/shuffle/\n\t// https://stackoverflow.com/a/2450976/6495043\n\t// https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array?noredirect=1&lq=1\n\n\tfor (let i = array.length - 1; i > 0; i--) {\n\t\tlet j = Math.floor(Math.random() * (i + 1));\n\t\t[array[i], array[j]] = [array[j], array[i]];\n\t}\n\n\treturn array;\n}\n\n/**\n * Fill an array with extra points\n * @param {Array} array Array\n * @param {Number} count number of filler elements\n * @param {Object} element element to fill with\n * @param {Boolean} start fill at start?\n */\nexport function fillArray(array, count, element, start=false) {\n\tif(!element) {\n\t\telement = start ? array[0] : array[array.length - 1];\n\t}\n\tlet fillerArray = new Array(Math.abs(count)).fill(element);\n\tarray = start ? fillerArray.concat(array) : array.concat(fillerArray);\n\treturn array;\n}\n\n/**\n * Returns pixel width of string.\n * @param {String} string\n * @param {Number} charWidth Width of single char in pixels\n */\nexport function getStringWidth(string, charWidth) {\n\treturn (string+\"\").length * charWidth;\n}\n\nexport function bindChange(obj, getFn, setFn) {\n\treturn new Proxy(obj, {\n\t\tset: function(target, prop, value) {\n\t\t\tsetFn();\n\t\t\treturn Reflect.set(target, prop, value);\n\t\t},\n\t\tget: function(target, prop) {\n\t\t\tgetFn();\n\t\t\treturn Reflect.get(target, prop);\n\t\t}\n\t});\n}\n\n// https://stackoverflow.com/a/29325222\nexport function getRandomBias(min, max, bias, influence) {\n\tconst range = max - min;\n\tconst biasValue = range * bias + min;\n\tvar rnd = Math.random() * range + min,\t\t// random in range\n\t\tmix = Math.random() * influence;\t\t// random mixer\n\treturn rnd * (1 - mix) + biasValue * mix;\t// mix full range and bias\n}\n\nexport function getPositionByAngle(angle, radius) {\n\treturn {\n\t\tx: Math.sin(angle * ANGLE_RATIO) * radius,\n\t\ty: Math.cos(angle * ANGLE_RATIO) * radius,\n\t};\n}\n\n/**\n * Check if a number is valid for svg attributes\n * @param {object} candidate Candidate to test\n * @param {Boolean} nonNegative flag to treat negative number as invalid\n */\nexport function isValidNumber(candidate, nonNegative=false) {\n\tif (Number.isNaN(candidate)) return false;\n\telse if (candidate === undefined) return false;\n\telse if (!Number.isFinite(candidate)) return false;\n\telse if (nonNegative && candidate < 0) return false;\n\telse return true;\n}\n\n/**\n * Round a number to the closes precision, max max precision 4\n * @param {Number} d Any Number\n */\nexport function round(d) {\n\t// https://floating-point-gui.de/\n\t// https://www.jacklmoore.com/notes/rounding-in-javascript/\n\treturn Number(Math.round(d + 'e4') + 'e-4');\n}\n\n/**\n * Creates a deep clone of an object\n * @param {Object} candidate Any Object\n */\n export function deepClone(candidate) {\n\tlet cloned, value, key;\n \n\tif (candidate instanceof Date) {\n\t return new Date(candidate.getTime());\n\t}\n \n\tif (typeof candidate !== \"object\" || candidate === null) {\n\t return candidate;\n\t}\n \n\tcloned = Array.isArray(candidate) ? [] : {};\n \n\tfor (key in candidate) {\n\t value = candidate[key];\n \n\t cloned[key] = deepClone(value);\n\t}\n \n\treturn cloned;\n }","import { fillArray } from './helpers';\n\nexport function getBarHeightAndYAttr(yTop, zeroLine) {\n\tlet height, y;\n\tif (yTop <= zeroLine) {\n\t\theight = zeroLine - yTop;\n\t\ty = yTop;\n\t} else {\n\t\theight = yTop - zeroLine;\n\t\ty = zeroLine;\n\t}\n\n\treturn [height, y];\n}\n\nexport function equilizeNoOfElements(array1, array2,\n\textraCount = array2.length - array1.length) {\n\n\t// Doesn't work if either has zero elements.\n\tif(extraCount > 0) {\n\t\tarray1 = fillArray(array1, extraCount);\n\t} else {\n\t\tarray2 = fillArray(array2, extraCount);\n\t}\n\treturn [array1, array2];\n}\n\nexport function truncateString(txt, len) {\n\tif (!txt) {\n\t\treturn;\n\t}\n\tif (txt.length > len) {\n\t\treturn txt.slice(0, len-3) + '...';\n\t} else {\n\t\treturn txt;\n\t}\n}\n\nexport function shortenLargeNumber(label) {\n\tlet number;\n\tif (typeof label === 'number') number = label;\n\telse if (typeof label === 'string') {\n\t\tnumber = Number(label);\n\t\tif (Number.isNaN(number)) return label;\n\t}\n\n\t// Using absolute since log wont work for negative numbers\n\tlet p = Math.floor(Math.log10(Math.abs(number)));\n\tif (p <= 2) return number; // Return as is for a 3 digit number of less\n\tlet\tl = Math.floor(p / 3);\n\tlet shortened = (Math.pow(10, p - l * 3) * +(number / Math.pow(10, p)).toFixed(1));\n\n\t// Correct for floating point error upto 2 decimal places\n\treturn Math.round(shortened*100)/100 + ' ' + ['', 'K', 'M', 'B', 'T'][l];\n}\n\n// cubic bezier curve calculation (from example by François Romain)\nexport function getSplineCurvePointsStr(xList, yList) {\n\n\tlet points=[];\n\tfor(let i=0;i {\n\t\tlet lengthX = pointB[0] - pointA[0];\n\t\tlet lengthY = pointB[1] - pointA[1];\n\t\treturn {\n\t\t\tlength: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),\n\t\t\tangle: Math.atan2(lengthY, lengthX)\n\t\t};\n\t};\n \n\tlet controlPoint = (current, previous, next, reverse) => {\n\t\tlet p = previous || current;\n\t\tlet n = next || current;\n\t\tlet o = line(p, n);\n\t\tlet angle = o.angle + (reverse ? Math.PI : 0);\n\t\tlet length = o.length * smoothing;\n\t\tlet x = current[0] + Math.cos(angle) * length;\n\t\tlet y = current[1] + Math.sin(angle) * length;\n\t\treturn [x, y];\n\t};\n \n\tlet bezierCommand = (point, i, a) => {\n\t\tlet cps = controlPoint(a[i - 1], a[i - 2], point);\n\t\tlet cpe = controlPoint(point, a[i - 1], a[i + 1], true);\n\t\treturn `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`;\n\t};\n \n\tlet pointStr = (points, command) => {\n\t\treturn points.reduce((acc, point, i, a) => i === 0\n\t\t\t? `${point[0]},${point[1]}`\n\t\t\t: `${acc} ${command(point, i, a)}`, '');\n\t};\n \n\treturn pointStr(points, bezierCommand);\n}\n","const PRESET_COLOR_MAP = {\n\t'light-blue': '#7cd6fd',\n\t'blue': '#5e64ff',\n\t'violet': '#743ee2',\n\t'red': '#ff5858',\n\t'orange': '#ffa00a',\n\t'yellow': '#feef72',\n\t'green': '#28a745',\n\t'light-green': '#98d85b',\n\t'purple': '#b554ff',\n\t'magenta': '#ffa3ef',\n\t'black': '#36114C',\n\t'grey': '#bdd3e6',\n\t'light-grey': '#f0f4f7',\n\t'dark-grey': '#b8c2cc'\n};\n\nfunction limitColor(r){\n\tif (r > 255) return 255;\n\telse if (r < 0) return 0;\n\treturn r;\n}\n\nexport function lightenDarkenColor(color, amt) {\n\tlet col = getColor(color);\n\tlet usePound = false;\n\tif (col[0] == \"#\") {\n\t\tcol = col.slice(1);\n\t\tusePound = true;\n\t}\n\tlet num = parseInt(col,16);\n\tlet r = limitColor((num >> 16) + amt);\n\tlet b = limitColor(((num >> 8) & 0x00FF) + amt);\n\tlet g = limitColor((num & 0x0000FF) + amt);\n\treturn (usePound?\"#\":\"\") + (g | (b << 8) | (r << 16)).toString(16);\n}\n\nexport function isValidColor(string) {\n\t// https://stackoverflow.com/a/32685393\n\tlet HEX_RE = /(^\\s*)(#)((?:[A-Fa-f0-9]{3}){1,2})$/i;\n\tlet RGB_RE = /(^\\s*)(rgb|hsl)(a?)[(]\\s*([\\d.]+\\s*%?)\\s*,\\s*([\\d.]+\\s*%?)\\s*,\\s*([\\d.]+\\s*%?)\\s*(?:,\\s*([\\d.]+)\\s*)?[)]$/i;\n\treturn HEX_RE.test(string) || RGB_RE.test(string);\n}\n\nexport const getColor = (color) => {\n\t// When RGB color, convert to hexadecimal (alpha value is omitted)\n\tif((/rgb[a]{0,1}\\([\\d, ]+\\)/gim).test(color)) {\n\t\treturn (/\\D+(\\d*)\\D+(\\d*)\\D+(\\d*)/gim).exec(color)\n\t\t\t.map((x, i) => (i !== 0 ? Number(x).toString(16) : '#'))\n\t\t\t.reduce((c, ch) => `${c}${ch}`);\n\t}\n\treturn PRESET_COLOR_MAP[color] || color;\n};\n","import { getBarHeightAndYAttr, truncateString, shortenLargeNumber, getSplineCurvePointsStr } from './draw-utils';\nimport { getStringWidth, isValidNumber } from './helpers';\nimport { DOT_OVERLAY_SIZE_INCR, PERCENTAGE_BAR_DEFAULT_DEPTH } from './constants';\nimport { lightenDarkenColor } from './colors';\n\nexport const AXIS_TICK_LENGTH = 6;\nconst LABEL_MARGIN = 4;\nconst LABEL_MAX_CHARS = 15;\nexport const FONT_SIZE = 10;\nconst BASE_LINE_COLOR = '#dadada';\nconst FONT_FILL = '#555b51';\n\nfunction $(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\nexport function createSVG(tag, o) {\n\tvar element = document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tif(i === \"className\") { i = \"class\"; }\n\t\t\tif(i === \"innerHTML\") {\n\t\t\t\telement['textContent'] = val;\n\t\t\t} else {\n\t\t\t\telement.setAttribute(i, val);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n}\n\nfunction renderVerticalGradient(svgDefElem, gradientId) {\n\treturn createSVG('linearGradient', {\n\t\tinside: svgDefElem,\n\t\tid: gradientId,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: 0,\n\t\ty2: 1\n\t});\n}\n\nfunction setGradientStop(gradElem, offset, color, opacity) {\n\treturn createSVG('stop', {\n\t\t'inside': gradElem,\n\t\t'style': `stop-color: ${color}`,\n\t\t'offset': offset,\n\t\t'stop-opacity': opacity\n\t});\n}\n\nexport function makeSVGContainer(parent, className, width, height) {\n\treturn createSVG('svg', {\n\t\tclassName: className,\n\t\tinside: parent,\n\t\twidth: width,\n\t\theight: height\n\t});\n}\n\nexport function makeSVGDefs(svgContainer) {\n\treturn createSVG('defs', {\n\t\tinside: svgContainer,\n\t});\n}\n\nexport function makeSVGGroup(className, transform='', parent=undefined) {\n\tlet args = {\n\t\tclassName: className,\n\t\ttransform: transform\n\t};\n\tif(parent) args.inside = parent;\n\treturn createSVG('g', args);\n}\n\nexport function wrapInSVGGroup(elements, className='') {\n\tlet g = createSVG('g', {\n\t\tclassName: className\n\t});\n\telements.forEach(e => g.appendChild(e));\n\treturn g;\n}\n\nexport function makePath(pathStr, className='', stroke='none', fill='none', strokeWidth=2) {\n\treturn createSVG('path', {\n\t\tclassName: className,\n\t\td: pathStr,\n\t\tstyles: {\n\t\t\tstroke: stroke,\n\t\t\tfill: fill,\n\t\t\t'stroke-width': strokeWidth\n\t\t}\n\t});\n}\n\nexport function makeArcPathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];\n\treturn `M${center.x} ${center.y}\n\t\tL${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY} z`;\n}\n\nexport function makeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, center.y * 2, center.y + endPosition.y];\n\treturn `M${center.x} ${center.y}\n\t\tL${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${midArc} z\n\t\tL${arcStartX} ${midArc}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY} z`;\n}\n\nexport function makeArcStrokePathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];\n\n\treturn `M${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY}`;\n}\n\nexport function makeStrokeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, radius * 2 + arcStartY, center.y + startPosition.y];\n\n\treturn `M${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${midArc}\n\t\tM${arcStartX} ${midArc}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY}`;\n}\n\nexport function makeGradient(svgDefElem, color, lighter = false) {\n\tlet gradientId ='path-fill-gradient' + '-' + color + '-' +(lighter ? 'lighter' : 'default');\n\tlet gradientDef = renderVerticalGradient(svgDefElem, gradientId);\n\tlet opacities = [1, 0.6, 0.2];\n\tif(lighter) {\n\t\topacities = [0.4, 0.2, 0];\n\t}\n\n\tsetGradientStop(gradientDef, \"0%\", color, opacities[0]);\n\tsetGradientStop(gradientDef, \"50%\", color, opacities[1]);\n\tsetGradientStop(gradientDef, \"100%\", color, opacities[2]);\n\n\treturn gradientId;\n}\n\nexport function percentageBar(x, y, width, height,\n\tdepth=PERCENTAGE_BAR_DEFAULT_DEPTH, fill='none') {\n\n\tlet args = {\n\t\tclassName: 'percentage-bar',\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height,\n\t\tfill: fill,\n\t\tstyles: {\n\t\t\t'stroke': lightenDarkenColor(fill, -25),\n\t\t\t// Diabolically good: https://stackoverflow.com/a/9000859\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray\n\t\t\t'stroke-dasharray': `0, ${height + width}, ${width}, ${height}`,\n\t\t\t'stroke-width': depth\n\t\t},\n\t};\n\n\treturn createSVG(\"rect\", args);\n}\n\nexport function heatSquare(className, x, y, size, radius, fill='none', data={}) {\n\tlet args = {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: size,\n\t\theight: size,\n\t\trx: radius,\n\t\tfill: fill\n\t};\n\n\tObject.keys(data).map(key => {\n\t\targs[key] = data[key];\n\t});\n\n\treturn createSVG(\"rect\", args);\n}\n\nexport function legendBar(x, y, size, fill='none', label, truncate=false) {\n\tlabel = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;\n\n\tlet args = {\n\t\tclassName: 'legend-bar',\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: size,\n\t\theight: '2px',\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE * 2) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"rect\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nexport function legendDot(x, y, size, fill='none', label, truncate=false) {\n\tlabel = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;\n\n\tlet args = {\n\t\tclassName: 'legend-dot',\n\t\tcx: 0,\n\t\tcy: 0,\n\t\tr: size,\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdx: (FONT_SIZE) + 'px',\n\t\tdy: (FONT_SIZE/3) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"circle\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nexport function makeText(className, x, y, content, options = {}) {\n\tlet fontSize = options.fontSize || FONT_SIZE;\n\tlet dy = options.dy !== undefined ? options.dy : (fontSize / 2);\n\tlet fill = options.fill || FONT_FILL;\n\tlet textAnchor = options.textAnchor || 'start';\n\treturn createSVG('text', {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\tdy: dy + 'px',\n\t\t'font-size': fontSize + 'px',\n\t\tfill: fill,\n\t\t'text-anchor': textAnchor,\n\t\tinnerHTML: content\n\t});\n}\n\nfunction makeVertLine(x, label, y1, y2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tlet l = createSVG('line', {\n\t\tclassName: 'line-vertical ' + options.className,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: y1,\n\t\ty2: y2,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: 0,\n\t\ty: y1 > y2 ? y1 + LABEL_MARGIN : y1 - LABEL_MARGIN - FONT_SIZE,\n\t\tdy: FONT_SIZE + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'middle',\n\t\tinnerHTML: label + \"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(${ x }, 0)`\n\t});\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nfunction makeHoriLine(y, label, x1, x2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.lineType) options.lineType = '';\n\tif (options.shortenNumbers) label = shortenLargeNumber(label);\n\n\tlet className = 'line-horizontal ' + options.className +\n\t\t(options.lineType === \"dashed\" ? \"dashed\": \"\");\n\n\tlet l = createSVG('line', {\n\t\tclassName: className,\n\t\tx1: x1,\n\t\tx2: x2,\n\t\ty1: 0,\n\t\ty2: 0,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: x1 < x2 ? x1 - LABEL_MARGIN : x1 + LABEL_MARGIN,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / 2 - 2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': x1 < x2 ? 'end' : 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(0, ${y})`,\n\t\t'stroke-opacity': 1\n\t});\n\n\tif(text === 0 || text === '0') {\n\t\tline.style.stroke = \"rgba(27, 31, 35, 0.6)\";\n\t}\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nexport function yLine(y, label, width, options={}) {\n\tif (!isValidNumber(y)) y = 0;\n\n\tif(!options.pos) options.pos = 'left';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\tlet x1 = -1 * AXIS_TICK_LENGTH;\n\tlet x2 = options.mode === 'span' ? width + AXIS_TICK_LENGTH : 0;\n\n\tif(options.mode === 'tick' && options.pos === 'right') {\n\t\tx1 = width + AXIS_TICK_LENGTH;\n\t\tx2 = width;\n\t}\n\n\t// let offset = options.pos === 'left' ? -1 * options.offset : options.offset;\n\n\tx1 += options.offset;\n\tx2 += options.offset;\n\n\treturn makeHoriLine(y, label, x1, x2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType,\n\t\tshortenNumbers: options.shortenNumbers\n\t});\n}\n\nexport function xLine(x, label, height, options={}) {\n\tif (!isValidNumber(x)) x = 0;\n\n\tif(!options.pos) options.pos = 'bottom';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\t// Draw X axis line in span/tick mode with optional label\n\t// \ty2(span)\n\t// \t\t\t\t\t\t|\n\t// \t\t\t\t\t\t|\n\t//\t\t\t\tx line\t|\n\t//\t\t\t\t\t\t|\n\t// \t\t\t\t\t \t|\n\t// ---------------------+-- y2(tick)\n\t//\t\t\t\t\t\t|\n\t//\t\t\t\t\t\t\ty1\n\n\tlet y1 = height + AXIS_TICK_LENGTH;\n\tlet y2 = options.mode === 'span' ? -1 * AXIS_TICK_LENGTH : height;\n\n\tif(options.mode === 'tick' && options.pos === 'top') {\n\t\t// top axis ticks\n\t\ty1 = -1 * AXIS_TICK_LENGTH;\n\t\ty2 = 0;\n\t}\n\n\treturn makeVertLine(x, label, y1, y2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType\n\t});\n}\n\nexport function yMarker(y, label, width, options={}) {\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label, 5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = makeHoriLine(y, '', 0, width, {\n\t\tstroke: options.stroke || BASE_LINE_COLOR,\n\t\tclassName: options.className || '',\n\t\tlineType: options.lineType\n\t});\n\n\tline.appendChild(labelSvg);\n\n\treturn line;\n}\n\nexport function yRegion(y1, y2, width, label, options={}) {\n\t// return a group\n\tlet height = y1 - y2;\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`, // remove class\n\t\tstyles: {\n\t\t\tfill: `rgba(228, 234, 239, 0.49)`,\n\t\t\tstroke: BASE_LINE_COLOR,\n\t\t\t'stroke-dasharray': `${width}, ${height}`\n\t\t},\n\t\t// 'data-point-index': index,\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label+\"\", 4.5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet region = createSVG('g', {\n\t\ttransform: `translate(0, ${y2})`\n\t});\n\n\tregion.appendChild(rect);\n\tregion.appendChild(labelSvg);\n\n\treturn region;\n}\n\nexport function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\n\tif(height === 0) {\n\t\theight = meta.minHeight;\n\t\ty -= meta.minHeight;\n\t}\n\n\t// Preprocess numbers to avoid svg building errors\n\tif (!isValidNumber(x)) x = 0;\n\tif (!isValidNumber(y)) y = 0;\n\tif (!isValidNumber(height, true)) height = 0;\n\tif (!isValidNumber(width, true)) width = 0;\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`,\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn rect;\n\t} else {\n\t\trect.setAttribute('y', 0);\n\t\trect.setAttribute('x', 0);\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: width/2,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(rect);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nexport function datasetDot(x, y, radius, color, label='', index=0) {\n\tlet dot = createSVG('circle', {\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tcx: x,\n\t\tcy: y,\n\t\tr: radius\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn dot;\n\t} else {\n\t\tdot.setAttribute('cy', 0);\n\t\tdot.setAttribute('cx', 0);\n\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1 - radius) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(dot);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nexport function getPaths(xList, yList, color, options={}, meta={}) {\n\tlet pointsList = yList.map((y, i) => (xList[i] + ',' + y));\n\tlet pointsStr = pointsList.join(\"L\");\n\n\t// Spline\n\tif (options.spline)\n\t\tpointsStr = getSplineCurvePointsStr(xList, yList);\n\n\tlet path = makePath(\"M\"+pointsStr, 'line-graph-path', color);\n\n\t// HeatLine\n\tif(options.heatline) {\n\t\tlet gradient_id = makeGradient(meta.svgDefs, color);\n\t\tpath.style.stroke = `url(#${gradient_id})`;\n\t}\n\n\tlet paths = {\n\t\tpath: path\n\t};\n\n\t// Region\n\tif(options.regionFill) {\n\t\tlet gradient_id_region = makeGradient(meta.svgDefs, color, true);\n\n\t\tlet pathStr = \"M\" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`;\n\t\tpaths.region = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`);\n\t}\n\n\treturn paths;\n}\n\nexport let makeOverlay = {\n\t'bar': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\toverlay.style.fill = '#000000';\n\t\toverlay.style.opacity = '0.4';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'dot': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'heat_square': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t}\n};\n\nexport let updateOverlay = {\n\t'bar': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['x', 'y', 'width', 'height'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'dot': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'heat_square': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n};\n","import { getBarHeightAndYAttr, getSplineCurvePointsStr } from './draw-utils';\n\nexport const UNIT_ANIM_DUR = 350;\nexport const PATH_ANIM_DUR = 350;\nexport const MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR;\nexport const REPLACE_ALL_NEW_DUR = 250;\n\nexport const STD_EASING = 'easein';\n\nexport function translate(unit, oldCoord, newCoord, duration) {\n\tlet old = typeof oldCoord === 'string' ? oldCoord : oldCoord.join(', ');\n\treturn [\n\t\tunit,\n\t\t{transform: newCoord.join(', ')},\n\t\tduration,\n\t\tSTD_EASING,\n\t\t\"translate\",\n\t\t{transform: old}\n\t];\n}\n\nexport function translateVertLine(xLine, newX, oldX) {\n\treturn translate(xLine, [oldX, 0], [newX, 0], MARKER_LINE_ANIM_DUR);\n}\n\nexport function translateHoriLine(yLine, newY, oldY) {\n\treturn translate(yLine, [0, oldY], [0, newY], MARKER_LINE_ANIM_DUR);\n}\n\nexport function animateRegion(rectGroup, newY1, newY2, oldY2) {\n\tlet newHeight = newY1 - newY2;\n\tlet rect = rectGroup.childNodes[0];\n\tlet width = rect.getAttribute(\"width\");\n\tlet rectAnim = [\n\t\trect,\n\t\t{ height: newHeight, 'stroke-dasharray': `${width}, ${newHeight}` },\n\t\tMARKER_LINE_ANIM_DUR,\n\t\tSTD_EASING\n\t];\n\n\tlet groupAnim = translate(rectGroup, [0, oldY2], [0, newY2], MARKER_LINE_ANIM_DUR);\n\treturn [rectAnim, groupAnim];\n}\n\nexport function animateBar(bar, x, yTop, width, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\tif(bar.nodeName !== 'rect') {\n\t\tlet rect = bar.childNodes[0];\n\t\tlet rectAnim = [\n\t\t\trect,\n\t\t\t{width: width, height: height},\n\t\t\tUNIT_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\n\t\tlet oldCoordStr = bar.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(bar, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [rectAnim, groupAnim];\n\t} else {\n\t\treturn [[bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nexport function animateDot(dot, x, y) {\n\tif(dot.nodeName !== 'circle') {\n\t\tlet oldCoordStr = dot.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(dot, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [groupAnim];\n\t} else {\n\t\treturn [[dot, {cx: x, cy: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nexport function animatePath(paths, newXList, newYList, zeroLine, spline) {\n\tlet pathComponents = [];\n\tlet pointsStr = newYList.map((y, i) => (newXList[i] + ',' + y)).join(\"L\");\n\n\tif (spline)\n\t\tpointsStr = getSplineCurvePointsStr(newXList, newYList);\n\n\tconst animPath = [paths.path, {d:\"M\" + pointsStr}, PATH_ANIM_DUR, STD_EASING];\n\tpathComponents.push(animPath);\n\n\tif(paths.region) {\n\t\tlet regStartPt = `${newXList[0]},${zeroLine}L`;\n\t\tlet regEndPt = `L${newXList.slice(-1)[0]}, ${zeroLine}`;\n\n\t\tconst animRegion = [\n\t\t\tpaths.region,\n\t\t\t{d:\"M\" + regStartPt + pointsStr + regEndPt},\n\t\t\tPATH_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\t\tpathComponents.push(animRegion);\n\t}\n\n\treturn pathComponents;\n}\n\nexport function animatePathStr(oldPath, pathStr) {\n\treturn [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING];\n}\n","// Leveraging SMIL Animations\n\nimport { REPLACE_ALL_NEW_DUR } from './animate';\n\nconst EASING = {\n\tease: \"0.25 0.1 0.25 1\",\n\tlinear: \"0 0 1 1\",\n\t// easein: \"0.42 0 1 1\",\n\teasein: \"0.1 0.8 0.2 1\",\n\teaseout: \"0 0 0.58 1\",\n\teaseinout: \"0.42 0 0.58 1\"\n};\n\nfunction animateSVGElement(element, props, dur, easingType=\"linear\", type=undefined, oldValues={}) {\n\n\tlet animElement = element.cloneNode(true);\n\tlet newElement = element.cloneNode(true);\n\n\tfor(var attributeName in props) {\n\t\tlet animateElement;\n\t\tif(attributeName === 'transform') {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animateTransform\");\n\t\t} else {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animate\");\n\t\t}\n\t\tlet currentValue = oldValues[attributeName] || element.getAttribute(attributeName);\n\t\tlet value = props[attributeName];\n\n\t\tlet animAttr = {\n\t\t\tattributeName: attributeName,\n\t\t\tfrom: currentValue,\n\t\t\tto: value,\n\t\t\tbegin: \"0s\",\n\t\t\tdur: dur/1000 + \"s\",\n\t\t\tvalues: currentValue + \";\" + value,\n\t\t\tkeySplines: EASING[easingType],\n\t\t\tkeyTimes: \"0;1\",\n\t\t\tcalcMode: \"spline\",\n\t\t\tfill: 'freeze'\n\t\t};\n\n\t\tif(type) {\n\t\t\tanimAttr[\"type\"] = type;\n\t\t}\n\n\t\tfor (var i in animAttr) {\n\t\t\tanimateElement.setAttribute(i, animAttr[i]);\n\t\t}\n\n\t\tanimElement.appendChild(animateElement);\n\n\t\tif(type) {\n\t\t\tnewElement.setAttribute(attributeName, `translate(${value})`);\n\t\t} else {\n\t\t\tnewElement.setAttribute(attributeName, value);\n\t\t}\n\t}\n\n\treturn [animElement, newElement];\n}\n\nexport function transform(element, style) { // eslint-disable-line no-unused-vars\n\telement.style.transform = style;\n\telement.style.webkitTransform = style;\n\telement.style.msTransform = style;\n\telement.style.mozTransform = style;\n\telement.style.oTransform = style;\n}\n\nfunction animateSVG(svgContainer, elements) {\n\tlet newElements = [];\n\tlet animElements = [];\n\n\telements.map(element => {\n\t\tlet unit = element[0];\n\t\tlet parent = unit.parentNode;\n\n\t\tlet animElement, newElement;\n\n\t\telement[0] = unit;\n\t\t[animElement, newElement] = animateSVGElement(...element);\n\n\t\tnewElements.push(newElement);\n\t\tanimElements.push([animElement, parent]);\n\t\t\n\t\tif (parent) {\n\t\t\tparent.replaceChild(animElement, unit);\n\t\t}\n\t});\n\n\tlet animSvg = svgContainer.cloneNode(true);\n\n\tanimElements.map((animElement, i) => {\n\t\tif (animElement[1]) {\n\t\t\tanimElement[1].replaceChild(newElements[i], animElement[0]);\n\t\t\telements[i][0] = newElements[i];\n\t\t}\n\t});\n\n\treturn animSvg;\n}\n\nexport function runSMILAnimation(parent, svgElement, elementsToAnimate) {\n\tif(elementsToAnimate.length === 0) return;\n\n\tlet animSvgElement = animateSVG(svgElement, elementsToAnimate);\n\tif(svgElement.parentNode == parent) {\n\t\tparent.removeChild(svgElement);\n\t\tparent.appendChild(animSvgElement);\n\n\t}\n\n\t// Replace the new svgElement (data has already been replaced)\n\tsetTimeout(() => {\n\t\tif(animSvgElement.parentNode == parent) {\n\t\t\tparent.removeChild(animSvgElement);\n\t\t\tparent.appendChild(svgElement);\n\t\t}\n\t}, REPLACE_ALL_NEW_DUR);\n}\n","import { $ } from '../utils/dom';\nimport { CSSTEXT } from '../../css/chartsCss';\n\nexport function downloadFile(filename, data) {\n\tvar a = document.createElement('a');\n\ta.style = \"display: none\";\n\tvar blob = new Blob(data, {type: \"image/svg+xml; charset=utf-8\"});\n\tvar url = window.URL.createObjectURL(blob);\n\ta.href = url;\n\ta.download = filename;\n\tdocument.body.appendChild(a);\n\ta.click();\n\tsetTimeout(function(){\n\t\tdocument.body.removeChild(a);\n\t\twindow.URL.revokeObjectURL(url);\n\t}, 300);\n}\n\nexport function prepareForExport(svg) {\n\tlet clone = svg.cloneNode(true);\n\tclone.classList.add('chart-container');\n\tclone.setAttribute('xmlns', \"http://www.w3.org/2000/svg\");\n\tclone.setAttribute('xmlns:xlink', \"http://www.w3.org/1999/xlink\");\n\tlet styleEl = $.create('style', {\n\t\t'innerHTML': CSSTEXT\n\t});\n\tclone.insertBefore(styleEl, clone.firstChild);\n\n\tlet container = $.create('div');\n\tcontainer.appendChild(clone);\n\n\treturn container.innerHTML;\n}\n","// Playing around with dates\n\nexport const NO_OF_YEAR_MONTHS = 12;\nexport const NO_OF_DAYS_IN_WEEK = 7;\nexport const DAYS_IN_YEAR = 375;\nexport const NO_OF_MILLIS = 1000;\nexport const SEC_IN_DAY = 86400;\n\nexport const MONTH_NAMES = [\"January\", \"February\", \"March\", \"April\", \"May\",\n\t\"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"];\nexport const MONTH_NAMES_SHORT = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n\t\"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n\nexport const DAY_NAMES_SHORT = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\nexport const DAY_NAMES = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\",\n\t\"Thursday\", \"Friday\", \"Saturday\"];\n\n// https://stackoverflow.com/a/11252167/6495043\nfunction treatAsUtc(date) {\n\tlet result = new Date(date);\n\tresult.setMinutes(result.getMinutes() - result.getTimezoneOffset());\n\treturn result;\n}\n\nexport function getYyyyMmDd(date) {\n\tlet dd = date.getDate();\n\tlet mm = date.getMonth() + 1; // getMonth() is zero-based\n\treturn [\n\t\tdate.getFullYear(),\n\t\t(mm>9 ? '' : '0') + mm,\n\t\t(dd>9 ? '' : '0') + dd\n\t].join('-');\n}\n\nexport function clone(date) {\n\treturn new Date(date.getTime());\n}\n\nexport function timestampSec(date) {\n\treturn date.getTime()/NO_OF_MILLIS;\n}\n\nexport function timestampToMidnight(timestamp, roundAhead = false) {\n\tlet midnightTs = Math.floor(timestamp - (timestamp % SEC_IN_DAY));\n\tif(roundAhead) {\n\t\treturn midnightTs + SEC_IN_DAY;\n\t}\n\treturn midnightTs;\n}\n\n// export function getMonthsBetween(startDate, endDate) {}\n\nexport function getWeeksBetween(startDate, endDate) {\n\tlet weekStartDate = setDayToSunday(startDate);\n\treturn Math.ceil(getDaysBetween(weekStartDate, endDate) / NO_OF_DAYS_IN_WEEK);\n}\n\nexport function getDaysBetween(startDate, endDate) {\n\tlet millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS;\n\treturn (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay;\n}\n\nexport function areInSameMonth(startDate, endDate) {\n\treturn startDate.getMonth() === endDate.getMonth()\n\t\t&& startDate.getFullYear() === endDate.getFullYear();\n}\n\nexport function getMonthName(i, short=false) {\n\tlet monthName = MONTH_NAMES[i];\n\treturn short ? monthName.slice(0, 3) : monthName;\n}\n\nexport function getLastDateInMonth (month, year) {\n\treturn new Date(year, month + 1, 0); // 0: last day in previous month\n}\n\n// mutates\nexport function setDayToSunday(date) {\n\tlet newDate = clone(date);\n\tconst day = newDate.getDay();\n\tif(day !== 0) {\n\t\taddDays(newDate, (-1) * day);\n\t}\n\treturn newDate;\n}\n\n// mutates\nexport function addDays(date, numberOfDays) {\n\tdate.setDate(date.getDate() + numberOfDays);\n}\n","import { makeSVGGroup } from '../utils/draw';\nimport { makeText, makePath, xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, percentageBar, getPaths, heatSquare } from '../utils/draw';\nimport { equilizeNoOfElements } from '../utils/draw-utils';\nimport { translateHoriLine, translateVertLine, animateRegion, animateBar,\n\tanimateDot, animatePath, animatePathStr } from '../utils/animate';\nimport { getMonthName } from '../utils/date-utils';\n\nclass ChartComponent {\n\tconstructor({\n\t\tlayerClass = '',\n\t\tlayerTransform = '',\n\t\tconstants,\n\n\t\tgetData,\n\t\tmakeElements,\n\t\tanimateElements\n\t}) {\n\t\tthis.layerTransform = layerTransform;\n\t\tthis.constants = constants;\n\n\t\tthis.makeElements = makeElements;\n\t\tthis.getData = getData;\n\n\t\tthis.animateElements = animateElements;\n\n\t\tthis.store = [];\n\t\tthis.labels = [];\n\n\t\tthis.layerClass = layerClass;\n\t\tthis.layerClass = typeof(this.layerClass) === 'function'\n\t\t\t? this.layerClass() : this.layerClass;\n\n\t\tthis.refresh();\n\t}\n\n\trefresh(data) {\n\t\tthis.data = data || this.getData();\n\t}\n\n\tsetup(parent) {\n\t\tthis.layer = makeSVGGroup(this.layerClass, this.layerTransform, parent);\n\t}\n\n\tmake() {\n\t\tthis.render(this.data);\n\t\tthis.oldData = this.data;\n\t}\n\n\trender(data) {\n\t\tthis.store = this.makeElements(data);\n\n\t\tthis.layer.textContent = '';\n\t\tthis.store.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t\tthis.labels.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t}\n\n\tupdate(animate = true) {\n\t\tthis.refresh();\n\t\tlet animateElements = [];\n\t\tif(animate) {\n\t\t\tanimateElements = this.animateElements(this.data) || [];\n\t\t}\n\t\treturn animateElements;\n\t}\n}\n\nlet componentConfigs = {\n\tdonutSlices: {\n\t\tlayerClass: 'donut-slices',\n\t\tmakeElements(data) {\n\t\t\treturn data.sliceStrings.map((s, i) => {\n\t\t\t\tlet slice = makePath(s, 'donut-path', data.colors[i], 'none', data.strokeWidth);\n\t\t\t\tslice.style.transition = 'transform .3s;';\n\t\t\t\treturn slice;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\treturn this.store.map((slice, i) => animatePathStr(slice, newData.sliceStrings[i]));\n\t\t},\n\t},\n\tpieSlices: {\n\t\tlayerClass: 'pie-slices',\n\t\tmakeElements(data) {\n\t\t\treturn data.sliceStrings.map((s, i) =>{\n\t\t\t\tlet slice = makePath(s, 'pie-path', 'none', data.colors[i]);\n\t\t\t\tslice.style.transition = 'transform .3s;';\n\t\t\t\treturn slice;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\treturn this.store.map((slice, i) =>\n\t\t\t\tanimatePathStr(slice, newData.sliceStrings[i])\n\t\t\t);\n\t\t}\n\t},\n\tpercentageBars: {\n\t\tlayerClass: 'percentage-bars',\n\t\tmakeElements(data) {\n\t\t\treturn data.xPositions.map((x, i) =>{\n\t\t\t\tlet y = 0;\n\t\t\t\tlet bar = percentageBar(x, y, data.widths[i],\n\t\t\t\t\tthis.constants.barHeight, this.constants.barDepth, data.colors[i]);\n\t\t\t\treturn bar;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\tyAxis: {\n\t\tlayerClass: 'y axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\tyLine(position, data.labels[i], this.constants.width,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos, shortenNumbers: this.constants.shortenNumbers})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.labels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tlabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\txAxis: {\n\t\tlayerClass: 'x axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\txLine(position, data.calcLabels[i], this.constants.height,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.calcLabels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.calcLabels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tcalcLabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateVertLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyMarkers: {\n\t\tlayerClass: 'y-markers',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(m =>\n\t\t\t\tyMarker(m.position, m.label, this.constants.width,\n\t\t\t\t\t{labelPos: m.options.labelPos, mode: 'span', lineType: 'dashed'})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.position);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.position);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tposition: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyRegions: {\n\t\tlayerClass: 'y-regions',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(r =>\n\t\t\t\tyRegion(r.startPos, r.endPos, this.constants.width,\n\t\t\t\t\tr.label, {labelPos: r.options.labelPos})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.endPos);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newStarts = newData.map(d => d.startPos);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.endPos);\n\t\t\tlet oldStarts = this.oldData.map(d => d.startPos);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tstartPos: oldStarts[i],\n\t\t\t\t\tendPos: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((rectGroup, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateRegion(\n\t\t\t\t\trectGroup, newStarts[i], newPos[i], oldPos[i]\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\theatDomain: {\n\t\tlayerClass: function() { return 'heat-domain domain-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet {index, colWidth, rowHeight, squareSize, radius, xTranslate} = this.constants;\n\t\t\tlet monthNameHeight = -12;\n\t\t\tlet x = xTranslate, y = 0;\n\n\t\t\tthis.serializedSubDomains = [];\n\n\t\t\tdata.cols.map((week, weekNo) => {\n\t\t\t\tif(weekNo === 1) {\n\t\t\t\t\tthis.labels.push(\n\t\t\t\t\t\tmakeText('domain-name', x, monthNameHeight, getMonthName(index, true).toUpperCase(),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfontSize: 9\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tweek.map((day, i) => {\n\t\t\t\t\tif(day.fill) {\n\t\t\t\t\t\tlet data = {\n\t\t\t\t\t\t\t'data-date': day.yyyyMmDd,\n\t\t\t\t\t\t\t'data-value': day.dataValue,\n\t\t\t\t\t\t\t'data-day': i\n\t\t\t\t\t\t};\n\t\t\t\t\t\tlet square = heatSquare('day', x, y, squareSize, radius, day.fill, data);\n\t\t\t\t\t\tthis.serializedSubDomains.push(square);\n\t\t\t\t\t}\n\t\t\t\t\ty += rowHeight;\n\t\t\t\t});\n\t\t\t\ty = 0;\n\t\t\t\tx += colWidth;\n\t\t\t});\n\n\t\t\treturn this.serializedSubDomains;\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\n\tbarGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'bar';\n\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\treturn datasetBar(\n\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\ty,\n\t\t\t\t\tdata.barWidth,\n\t\t\t\t\tc.color,\n\t\t\t\t\tdata.labels[j],\n\t\t\t\t\tj,\n\t\t\t\t\tdata.offsets[j],\n\t\t\t\t\t{\n\t\t\t\t\t\tzeroLine: data.zeroLine,\n\t\t\t\t\t\tbarsWidth: data.barsWidth,\n\t\t\t\t\t\tminHeight: c.minHeight\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn this.units;\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newOffsets = newData.offsets;\n\t\t\tlet newLabels = newData.labels;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldOffsets = this.oldData.offsets;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldOffsets, newOffsets] = equilizeNoOfElements(oldOffsets, newOffsets);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\toffsets: oldOffsets,\n\t\t\t\tlabels: newLabels,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tbarsWidth: this.oldData.barsWidth,\n\t\t\t\tbarWidth: this.oldData.barWidth,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((bar, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateBar(\n\t\t\t\t\tbar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i],\n\t\t\t\t\t{zeroLine: newData.zeroLine}\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\tlineGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'dot';\n\t\t\tthis.paths = {};\n\t\t\tif(!c.hideLine) {\n\t\t\t\tthis.paths = getPaths(\n\t\t\t\t\tdata.xPositions,\n\t\t\t\t\tdata.yPositions,\n\t\t\t\t\tc.color,\n\t\t\t\t\t{\n\t\t\t\t\t\theatline: c.heatline,\n\t\t\t\t\t\tregionFill: c.regionFill,\n\t\t\t\t\t\tspline: c.spline\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsvgDefs: c.svgDefs,\n\t\t\t\t\t\tzeroLine: data.zeroLine\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.units = [];\n\t\t\tif(!c.hideDots) {\n\t\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\t\treturn datasetDot(\n\t\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\t\ty,\n\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\tc.color,\n\t\t\t\t\t\t(c.valuesOverPoints ? data.values[j] : ''),\n\t\t\t\t\t\tj\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn Object.values(this.paths).concat(this.units);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newValues = newData.values;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldValues = this.oldData.values;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldValues, newValues] = equilizeNoOfElements(oldValues, newValues);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\tvalues: newValues,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tradius: this.oldData.radius,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tif(Object.keys(this.paths).length) {\n\t\t\t\tanimateElements = animateElements.concat(animatePath(\n\t\t\t\t\tthis.paths, newXPos, newYPos, newData.zeroLine, this.constants.spline));\n\t\t\t}\n\n\t\t\tif(this.units.length) {\n\t\t\t\tthis.units.map((dot, i) => {\n\t\t\t\t\tanimateElements = animateElements.concat(animateDot(\n\t\t\t\t\t\tdot, newXPos[i], newYPos[i]));\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn animateElements;\n\t\t}\n\t}\n};\n\nexport function getComponent(name, constants, getData) {\n\tlet keys = Object.keys(componentConfigs).filter(k => name.includes(k));\n\tlet config = componentConfigs[keys[0]];\n\tObject.assign(config, {\n\t\tconstants: constants,\n\t\tgetData: getData\n\t});\n\treturn new ChartComponent(config);\n}\n","import { floatTwo } from './helpers';\n\nfunction normalize(x) {\n\t// Calculates mantissa and exponent of a number\n\t// Returns normalized number and exponent\n\t// https://stackoverflow.com/q/9383593/6495043\n\n\tif(x===0) {\n\t\treturn [0, 0];\n\t}\n\tif(isNaN(x)) {\n\t\treturn {mantissa: -6755399441055744, exponent: 972};\n\t}\n\tvar sig = x > 0 ? 1 : -1;\n\tif(!isFinite(x)) {\n\t\treturn {mantissa: sig * 4503599627370496, exponent: 972};\n\t}\n\n\tx = Math.abs(x);\n\tvar exp = Math.floor(Math.log10(x));\n\tvar man = x/Math.pow(10, exp);\n\n\treturn [sig * man, exp];\n}\n\nfunction getChartRangeIntervals(max, min=0) {\n\tlet upperBound = Math.ceil(max);\n\tlet lowerBound = Math.floor(min);\n\tlet range = upperBound - lowerBound;\n\n\tlet noOfParts = range;\n\tlet partSize = 1;\n\n\t// To avoid too many partitions\n\tif(range > 5) {\n\t\tif(range % 2 !== 0) {\n\t\t\tupperBound++;\n\t\t\t// Recalc range\n\t\t\trange = upperBound - lowerBound;\n\t\t}\n\t\tnoOfParts = range/2;\n\t\tpartSize = 2;\n\t}\n\n\t// Special case: 1 and 2\n\tif(range <= 2) {\n\t\tnoOfParts = 4;\n\t\tpartSize = range/noOfParts;\n\t}\n\n\t// Special case: 0\n\tif(range === 0) {\n\t\tnoOfParts = 5;\n\t\tpartSize = 1;\n\t}\n\n\tlet intervals = [];\n\tfor(var i = 0; i <= noOfParts; i++){\n\t\tintervals.push(lowerBound + partSize * i);\n\t}\n\treturn intervals;\n}\n\nfunction getChartIntervals(maxValue, minValue=0) {\n\tlet [normalMaxValue, exponent] = normalize(maxValue);\n\tlet normalMinValue = minValue ? minValue/Math.pow(10, exponent): 0;\n\n\t// Allow only 7 significant digits\n\tnormalMaxValue = normalMaxValue.toFixed(6);\n\n\tlet intervals = getChartRangeIntervals(normalMaxValue, normalMinValue);\n\tintervals = intervals.map(value => value * Math.pow(10, exponent));\n\treturn intervals;\n}\n\nexport function calcChartIntervals(values, withMinimum=false) {\n\t//*** Where the magic happens ***\n\n\t// Calculates best-fit y intervals from given values\n\t// and returns the interval array\n\n\tlet maxValue = Math.max(...values);\n\tlet minValue = Math.min(...values);\n\n\t// Exponent to be used for pretty print\n\tlet exponent = 0, intervals = []; // eslint-disable-line no-unused-vars\n\n\tfunction getPositiveFirstIntervals(maxValue, absMinValue) {\n\t\tlet intervals = getChartIntervals(maxValue);\n\n\t\tlet intervalSize = intervals[1] - intervals[0];\n\n\t\t// Then unshift the negative values\n\t\tlet value = 0;\n\t\tfor(var i = 1; value < absMinValue; i++) {\n\t\t\tvalue += intervalSize;\n\t\t\tintervals.unshift((-1) * value);\n\t\t}\n\t\treturn intervals;\n\t}\n\n\t// CASE I: Both non-negative\n\n\tif(maxValue >= 0 && minValue >= 0) {\n\t\texponent = normalize(maxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(maxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(maxValue, minValue);\n\t\t}\n\t}\n\n\t// CASE II: Only minValue negative\n\n\telse if(maxValue > 0 && minValue < 0) {\n\t\t// `withMinimum` irrelevant in this case,\n\t\t// We'll be handling both sides of zero separately\n\t\t// (both starting from zero)\n\t\t// Because ceil() and floor() behave differently\n\t\t// in those two regions\n\n\t\tlet absMinValue = Math.abs(minValue);\n\n\t\tif(maxValue >= absMinValue) {\n\t\t\texponent = normalize(maxValue)[1];\n\t\t\tintervals = getPositiveFirstIntervals(maxValue, absMinValue);\n\t\t} else {\n\t\t\t// Mirror: maxValue => absMinValue, then change sign\n\t\t\texponent = normalize(absMinValue)[1];\n\t\t\tlet posIntervals = getPositiveFirstIntervals(absMinValue, maxValue);\n\t\t\tintervals = posIntervals.reverse().map(d => d * (-1));\n\t\t}\n\n\t}\n\n\t// CASE III: Both non-positive\n\n\telse if(maxValue <= 0 && minValue <= 0) {\n\t\t// Mirrored Case I:\n\t\t// Work with positives, then reverse the sign and array\n\n\t\tlet pseudoMaxValue = Math.abs(minValue);\n\t\tlet pseudoMinValue = Math.abs(maxValue);\n\n\t\texponent = normalize(pseudoMaxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue, pseudoMinValue);\n\t\t}\n\n\t\tintervals = intervals.reverse().map(d => d * (-1));\n\t}\n\n\treturn intervals;\n}\n\nexport function getZeroIndex(yPts) {\n\tlet zeroIndex;\n\tlet interval = getIntervalSize(yPts);\n\tif(yPts.indexOf(0) >= 0) {\n\t\t// the range has a given zero\n\t\t// zero-line on the chart\n\t\tzeroIndex = yPts.indexOf(0);\n\t} else if(yPts[0] > 0) {\n\t\t// Minimum value is positive\n\t\t// zero-line is off the chart: below\n\t\tlet min = yPts[0];\n\t\tzeroIndex = (-1) * min / interval;\n\t} else {\n\t\t// Maximum value is negative\n\t\t// zero-line is off the chart: above\n\t\tlet max = yPts[yPts.length - 1];\n\t\tzeroIndex = (-1) * max / interval + (yPts.length - 1);\n\t}\n\treturn zeroIndex;\n}\n\nexport function getRealIntervals(max, noOfIntervals, min = 0, asc = 1) {\n\tlet range = max - min;\n\tlet part = range * 1.0 / noOfIntervals;\n\tlet intervals = [];\n\n\tfor(var i = 0; i <= noOfIntervals; i++) {\n\t\tintervals.push(min + part * i);\n\t}\n\n\treturn asc ? intervals : intervals.reverse();\n}\n\nexport function getIntervalSize(orderedArray) {\n\treturn orderedArray[1] - orderedArray[0];\n}\n\nexport function getValueRange(orderedArray) {\n\treturn orderedArray[orderedArray.length-1] - orderedArray[0];\n}\n\nexport function scale(val, yAxis) {\n\treturn floatTwo(yAxis.zeroLine - val * yAxis.scaleMultiplier);\n}\n\nexport function isInRange(val, min, max) {\n\treturn val > min && val < max;\n}\n\nexport function isInRange2D(coord, minCoord, maxCoord) {\n\treturn isInRange(coord[0], minCoord[0], maxCoord[0])\n\t\t&& isInRange(coord[1], minCoord[1], maxCoord[1]);\n}\n\nexport function getClosestInArray(goal, arr, index = false) {\n\tlet closest = arr.reduce(function(prev, curr) {\n\t\treturn (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);\n\t}, []);\n\n\treturn index ? arr.indexOf(closest) : closest;\n}\n\nexport function calcDistribution(values, distributionSize) {\n\t// Assume non-negative values,\n\t// implying distribution minimum at zero\n\n\tlet dataMaxValue = Math.max(...values);\n\n\tlet distributionStep = 1 / (distributionSize - 1);\n\tlet distribution = [];\n\n\tfor(var i = 0; i < distributionSize; i++) {\n\t\tlet checkpoint = dataMaxValue * (distributionStep * i);\n\t\tdistribution.push(checkpoint);\n\t}\n\n\treturn distribution;\n}\n\nexport function getMaxCheckpoint(value, distribution) {\n\treturn distribution.filter(d => d < value).length;\n}\n","import { fillArray } from '../utils/helpers';\nimport { DEFAULT_AXIS_CHART_TYPE, AXIS_DATASET_CHART_TYPES, DEFAULT_CHAR_WIDTH } from '../utils/constants';\n\nexport function dataPrep(data, type) {\n\tdata.labels = data.labels || [];\n\n\tlet datasetLength = data.labels.length;\n\n\t// Datasets\n\tlet datasets = data.datasets;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\tif(!datasets) {\n\t\t// default\n\t\tdatasets = [{\n\t\t\tvalues: zeroArray\n\t\t}];\n\t}\n\n\tdatasets.map(d=> {\n\t\t// Set values\n\t\tif(!d.values) {\n\t\t\td.values = zeroArray;\n\t\t} else {\n\t\t\t// Check for non values\n\t\t\tlet vals = d.values;\n\t\t\tvals = vals.map(val => (!isNaN(val) ? val : 0));\n\n\t\t\t// Trim or extend\n\t\t\tif(vals.length > datasetLength) {\n\t\t\t\tvals = vals.slice(0, datasetLength);\n\t\t\t} else {\n\t\t\t\tvals = fillArray(vals, datasetLength - vals.length, 0);\n\t\t\t}\n\t\t\td.values = vals;\n\t\t}\n\n\t\t// Set type\n\t\tif(!d.chartType ) {\n\t\t\tif(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;\n\t\t\td.chartType = type;\n\t\t}\n\n\t});\n\n\t// Markers\n\n\t// Regions\n\t// data.yRegions = data.yRegions || [];\n\tif(data.yRegions) {\n\t\tdata.yRegions.map(d => {\n\t\t\tif(d.end < d.start) {\n\t\t\t\t[d.start, d.end] = [d.end, d.start];\n\t\t\t}\n\t\t});\n\t}\n\n\treturn data;\n}\n\nexport function zeroDataPrep(realData) {\n\tlet datasetLength = realData.labels.length;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\n\tlet zeroData = {\n\t\tlabels: realData.labels.slice(0, -1),\n\t\tdatasets: realData.datasets.map(d => {\n\t\t\treturn {\n\t\t\t\tname: '',\n\t\t\t\tvalues: zeroArray.slice(0, -1),\n\t\t\t\tchartType: d.chartType\n\t\t\t};\n\t\t}),\n\t};\n\n\tif(realData.yMarkers) {\n\t\tzeroData.yMarkers = [\n\t\t\t{\n\t\t\t\tvalue: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\tif(realData.yRegions) {\n\t\tzeroData.yRegions = [\n\t\t\t{\n\t\t\t\tstart: 0,\n\t\t\t\tend: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\treturn zeroData;\n}\n\nexport function getShortenedLabels(chartWidth, labels=[], isSeries=true) {\n\tlet allowedSpace = chartWidth / labels.length;\n\tif(allowedSpace <= 0) allowedSpace = 1;\n\tlet allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;\n\n\tlet seriesMultiple;\n\tif(isSeries) {\n\t\t// Find the maximum label length for spacing calculations\n\t\tlet maxLabelLength = Math.max(...labels.map(label => label.length));\n\t\tseriesMultiple = Math.ceil(maxLabelLength/allowedLetters);\n\t}\n\n\tlet calcLabels = labels.map((label, i) => {\n\t\tlabel += \"\";\n\t\tif(label.length > allowedLetters) {\n\n\t\t\tif(!isSeries) {\n\t\t\t\tif(allowedLetters-3 > 0) {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters-3) + \" ...\";\n\t\t\t\t} else {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters) + '..';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(i % seriesMultiple !== 0) {\n\t\t\t\t\tlabel = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn label;\n\t});\n\n\treturn calcLabels;\n}\n","import '../css/charts.scss';\n\n// import MultiAxisChart from './charts/MultiAxisChart';\nimport PercentageChart from './charts/PercentageChart';\nimport PieChart from './charts/PieChart';\nimport Heatmap from './charts/Heatmap';\nimport AxisChart from './charts/AxisChart';\nimport DonutChart from './charts/DonutChart';\n\nconst chartTypes = {\n\tbar: AxisChart,\n\tline: AxisChart,\n\t// multiaxis: MultiAxisChart,\n\tpercentage: PercentageChart,\n\theatmap: Heatmap,\n\tpie: PieChart,\n\tdonut: DonutChart,\n};\n\nfunction getChartByType(chartType = 'line', parent, options) {\n\tif (chartType === 'axis-mixed') {\n\t\toptions.type = 'line';\n\t\treturn new AxisChart(parent, options);\n\t}\n\n\tif (!chartTypes[chartType]) {\n\t\tconsole.error(\"Undefined chart type: \" + chartType);\n\t\treturn;\n\t}\n\n\treturn new chartTypes[chartType](parent, options);\n}\n\nclass Chart {\n\tconstructor(parent, options) {\n\t\treturn getChartByType(options.type, parent, options);\n\t}\n}\n\nexport { Chart, PercentageChart, PieChart, Heatmap, AxisChart };","import { $ } from '../utils/dom';\nimport { TOOLTIP_POINTER_TRIANGLE_HEIGHT } from '../utils/constants';\n\nexport default class SvgTip {\n\tconstructor({\n\t\tparent = null,\n\t\tcolors = []\n\t}) {\n\t\tthis.parent = parent;\n\t\tthis.colors = colors;\n\t\tthis.titleName = '';\n\t\tthis.titleValue = '';\n\t\tthis.listValues = [];\n\t\tthis.titleValueFirst = 0;\n\n\t\tthis.x = 0;\n\t\tthis.y = 0;\n\n\t\tthis.top = 0;\n\t\tthis.left = 0;\n\n\t\tthis.setup();\n\t}\n\n\tsetup() {\n\t\tthis.makeTooltip();\n\t}\n\n\trefresh() {\n\t\tthis.fill();\n\t\tthis.calcPosition();\n\t}\n\n\tmakeTooltip() {\n\t\tthis.container = $.create('div', {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'graph-svg-tip comparison',\n\t\t\tinnerHTML: `\n\t\t\t\t
            \n\t\t\t\t
            `\n\t\t});\n\t\tthis.hideTip();\n\n\t\tthis.title = this.container.querySelector('.title');\n\t\tthis.dataPointList = this.container.querySelector('.data-point-list');\n\n\t\tthis.parent.addEventListener('mouseleave', () => {\n\t\t\tthis.hideTip();\n\t\t});\n\t}\n\n\tfill() {\n\t\tlet title;\n\t\tif(this.index) {\n\t\t\tthis.container.setAttribute('data-point-index', this.index);\n\t\t}\n\t\tif(this.titleValueFirst) {\n\t\t\ttitle = `${this.titleValue}${this.titleName}`;\n\t\t} else {\n\t\t\ttitle = `${this.titleName}${this.titleValue}`;\n\t\t}\n\t\tthis.title.innerHTML = title;\n\t\tthis.dataPointList.innerHTML = '';\n\n\t\tthis.listValues.map((set, i) => {\n\t\t\tconst color = this.colors[i] || 'black';\n\t\t\tlet value = set.formatted === 0 || set.formatted ? set.formatted : set.value;\n\n\t\t\tlet li = $.create('li', {\n\t\t\t\tstyles: {\n\t\t\t\t\t'border-top': `3px solid ${color}`\n\t\t\t\t},\n\t\t\t\tinnerHTML: `${ value === 0 || value ? value : '' }\n\t\t\t\t\t${set.title ? set.title : '' }`\n\t\t\t});\n\n\t\t\tthis.dataPointList.appendChild(li);\n\t\t});\n\t}\n\n\tcalcPosition() {\n\t\tlet width = this.container.offsetWidth;\n\n\t\tthis.top = this.y - this.container.offsetHeight\n\t\t\t- TOOLTIP_POINTER_TRIANGLE_HEIGHT;\n\t\tthis.left = this.x - width/2;\n\t\tlet maxLeft = this.parent.offsetWidth - width;\n\n\t\tlet pointer = this.container.querySelector('.svg-pointer');\n\n\t\tif(this.left < 0) {\n\t\t\tpointer.style.left = `calc(50% - ${-1 * this.left}px)`;\n\t\t\tthis.left = 0;\n\t\t} else if(this.left > maxLeft) {\n\t\t\tlet delta = this.left - maxLeft;\n\t\t\tlet pointerOffset = `calc(50% + ${delta}px)`;\n\t\t\tpointer.style.left = pointerOffset;\n\n\t\t\tthis.left = maxLeft;\n\t\t} else {\n\t\t\tpointer.style.left = `50%`;\n\t\t}\n\t}\n\n\tsetValues(x, y, title = {}, listValues = [], index = -1) {\n\t\tthis.titleName = title.name;\n\t\tthis.titleValue = title.value;\n\t\tthis.listValues = listValues;\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.titleValueFirst = title.valueFirst || 0;\n\t\tthis.index = index;\n\t\tthis.refresh();\n\t}\n\n\thideTip() {\n\t\tthis.container.style.top = '0px';\n\t\tthis.container.style.left = '0px';\n\t\tthis.container.style.opacity = '0';\n\t}\n\n\tshowTip() {\n\t\tthis.container.style.top = this.top + 'px';\n\t\tthis.container.style.left = this.left + 'px';\n\t\tthis.container.style.opacity = '1';\n\t}\n}\n","export const CSSTEXT = \".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}\";","import SvgTip from '../objects/SvgTip';\nimport { $, isElementInViewport, getElementContentWidth, isHidden } from '../utils/dom';\nimport { makeSVGContainer, makeSVGDefs, makeSVGGroup, makeText } from '../utils/draw';\nimport { BASE_MEASURES, getExtraHeight, getExtraWidth, getTopOffset, getLeftOffset,\n\tINIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS} from '../utils/constants';\nimport { getColor, isValidColor } from '../utils/colors';\nimport { runSMILAnimation } from '../utils/animation';\nimport { downloadFile, prepareForExport } from '../utils/export';\nimport { deepClone } from '../utils/helpers';\n\nexport default class BaseChart {\n\tconstructor(parent, options) {\n\t\t// deepclone options to avoid making changes to orignal object\n\t\toptions = deepClone(options);\n\n\t\tthis.parent = typeof parent === 'string'\n\t\t\t? document.querySelector(parent)\n\t\t\t: parent;\n\n\t\tif (!(this.parent instanceof HTMLElement)) {\n\t\t\tthrow new Error('No `parent` element to render on was provided.');\n\t\t}\n\n\t\tthis.rawChartArgs = options;\n\n\t\tthis.title = options.title || '';\n\t\tthis.type = options.type || '';\n\n\t\tthis.realData = this.prepareData(options.data);\n\t\tthis.data = this.prepareFirstData(this.realData);\n\n\t\tthis.colors = this.validateColors(options.colors, this.type);\n\n\t\tthis.config = {\n\t\t\tshowTooltip: 1, // calculate\n\t\t\tshowLegend: 1, // calculate\n\t\t\tisNavigable: options.isNavigable || 0,\n\t\t\tanimate: (typeof options.animate !== 'undefined') ? options.animate : 1,\n\t\t\ttruncateLegends: options.truncateLegends || 1\n\t\t};\n\n\t\tthis.measures = JSON.parse(JSON.stringify(BASE_MEASURES));\n\t\tlet m = this.measures;\n\t\tthis.setMeasures(options);\n\t\tif(!this.title.length) { m.titleHeight = 0; }\n\t\tif(!this.config.showLegend) m.legendHeight = 0;\n\t\tthis.argHeight = options.height || m.baseHeight;\n\n\t\tthis.state = {};\n\t\tthis.options = {};\n\n\t\tthis.initTimeout = INIT_CHART_UPDATE_TIMEOUT;\n\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.overlays = [];\n\t\t}\n\n\t\tthis.configure(options);\n\t}\n\n\tprepareData(data) {\n\t\treturn data;\n\t}\n\n\tprepareFirstData(data) {\n\t\treturn data;\n\t}\n\n\tvalidateColors(colors, type) {\n\t\tconst validColors = [];\n\t\tcolors = (colors || []).concat(DEFAULT_COLORS[type]);\n\t\tcolors.forEach((string) => {\n\t\t\tconst color = getColor(string);\n\t\t\tif(!isValidColor(color)) {\n\t\t\t\tconsole.warn('\"' + string + '\" is not a valid color.');\n\t\t\t} else {\n\t\t\t\tvalidColors.push(color);\n\t\t\t}\n\t\t});\n\t\treturn validColors;\n\t}\n\n\tsetMeasures() {\n\t\t// Override measures, including those for title and legend\n\t\t// set config for legend and title\n\t}\n\n\tconfigure() {\n\t\tlet height = this.argHeight;\n\t\tthis.baseHeight = height;\n\t\tthis.height = height - getExtraHeight(this.measures);\n\n\t\t// Bind window events\n\t\tthis.boundDrawFn = () => this.draw(true);\n\t\tif (ResizeObserver) {\n\t\t\tthis.resizeObserver = new ResizeObserver(this.boundDrawFn);\n\t\t\tthis.resizeObserver.observe(this.parent);\n\t\t}\n\t\twindow.addEventListener('resize', this.boundDrawFn);\n\t\twindow.addEventListener('orientationchange', this.boundDrawFn);\n\t}\n\n\tdestroy() {\n\t\tif (this.resizeObserver) this.resizeObserver.disconnect();\n\t\twindow.removeEventListener('resize', this.boundDrawFn);\n\t\twindow.removeEventListener('orientationchange', this.boundDrawFn);\n\t}\n\n\t// Has to be called manually\n\tsetup() {\n\t\tthis.makeContainer();\n\t\tthis.updateWidth();\n\t\tthis.makeTooltip();\n\n\t\tthis.draw(false, true);\n\t}\n\n\tmakeContainer() {\n\t\t// Chart needs a dedicated parent element\n\t\tthis.parent.innerHTML = '';\n\n\t\tlet args = {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'chart-container'\n\t\t};\n\n\t\tif(this.independentWidth) {\n\t\t\targs.styles = { width: this.independentWidth + 'px' };\n\t\t}\n\n\t\tthis.container = $.create('div', args);\n\t}\n\n\tmakeTooltip() {\n\t\tthis.tip = new SvgTip({\n\t\t\tparent: this.container,\n\t\t\tcolors: this.colors\n\t\t});\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {}\n\n\tdraw(onlyWidthChange=false, init=false) {\n\t\tif (onlyWidthChange && isHidden(this.parent)) {\n\t\t\t// Don't update anything if the chart is hidden\n\t\t\treturn;\n\t\t}\n\t\tthis.updateWidth();\n\n\t\tthis.calc(onlyWidthChange);\n\t\tthis.makeChartArea();\n\t\tthis.setupComponents();\n\n\t\tthis.components.forEach(c => c.setup(this.drawArea));\n\t\t// this.components.forEach(c => c.make());\n\t\tthis.render(this.components, false);\n\n\t\tif(init) {\n\t\t\tthis.data = this.realData;\n\t\t\tsetTimeout(() => {this.update(this.data);}, this.initTimeout);\n\t\t}\n\n\t\tthis.renderLegend();\n\n\t\tthis.setupNavigation(init);\n\t}\n\n\tcalc() {} // builds state\n\n\tupdateWidth() {\n\t\tthis.baseWidth = getElementContentWidth(this.parent);\n\t\tthis.width = this.baseWidth - getExtraWidth(this.measures);\n\t}\n\n\tmakeChartArea() {\n\t\tif(this.svg) {\n\t\t\tthis.container.removeChild(this.svg);\n\t\t}\n\t\tlet m = this.measures;\n\n\t\tthis.svg = makeSVGContainer(\n\t\t\tthis.container,\n\t\t\t'frappe-chart chart',\n\t\t\tthis.baseWidth,\n\t\t\tthis.baseHeight\n\t\t);\n\t\tthis.svgDefs = makeSVGDefs(this.svg);\n\n\t\tif(this.title.length) {\n\t\t\tthis.titleEL = makeText(\n\t\t\t\t'title',\n\t\t\t\tm.margins.left,\n\t\t\t\tm.margins.top,\n\t\t\t\tthis.title,\n\t\t\t\t{\n\t\t\t\t\tfontSize: m.titleFontSize,\n\t\t\t\t\tfill: '#666666',\n\t\t\t\t\tdy: m.titleFontSize\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tlet top = getTopOffset(m);\n\t\tthis.drawArea = makeSVGGroup(\n\t\t\tthis.type + '-chart chart-draw-area',\n\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t);\n\n\t\tif(this.config.showLegend) {\n\t\t\ttop += this.height + m.paddings.bottom;\n\t\t\tthis.legendArea = makeSVGGroup(\n\t\t\t\t'chart-legend',\n\t\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t\t);\n\t\t}\n\n\t\tif(this.title.length) { this.svg.appendChild(this.titleEL); }\n\t\tthis.svg.appendChild(this.drawArea);\n\t\tif(this.config.showLegend) { this.svg.appendChild(this.legendArea); }\n\n\t\tthis.updateTipOffset(getLeftOffset(m), getTopOffset(m));\n\t}\n\n\tupdateTipOffset(x, y) {\n\t\tthis.tip.offset = {\n\t\t\tx: x,\n\t\t\ty: y\n\t\t};\n\t}\n\n\tsetupComponents() { this.components = new Map(); }\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\t\tthis.data = this.prepareData(data);\n\t\tthis.calc(); // builds state\n\t\tthis.render(this.components, this.config.animate);\n\t\tthis.renderLegend();\n\t}\n\n\trender(components=this.components, animate=true) {\n\t\tif(this.config.isNavigable) {\n\t\t\t// Remove all existing overlays\n\t\t\tthis.overlays.map(o => o.parentNode.removeChild(o));\n\t\t\t// ref.parentNode.insertBefore(element, ref);\n\t\t}\n\t\tlet elementsToAnimate = [];\n\t\t// Can decouple to this.refreshComponents() first to save animation timeout\n\t\tcomponents.forEach(c => {\n\t\t\telementsToAnimate = elementsToAnimate.concat(c.update(animate));\n\t\t});\n\t\tif(elementsToAnimate.length > 0) {\n\t\t\trunSMILAnimation(this.container, this.svg, elementsToAnimate);\n\t\t\tsetTimeout(() => {\n\t\t\t\tcomponents.forEach(c => c.make());\n\t\t\t\tthis.updateNav();\n\t\t\t}, CHART_POST_ANIMATE_TIMEOUT);\n\t\t} else {\n\t\t\tcomponents.forEach(c => c.make());\n\t\t\tthis.updateNav();\n\t\t}\n\t}\n\n\tupdateNav() {\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.makeOverlay();\n\t\t\tthis.bindUnits();\n\t\t}\n\t}\n\n\trenderLegend() {}\n\n\tsetupNavigation(init=false) {\n\t\tif(!this.config.isNavigable) return;\n\n\t\tif(init) {\n\t\t\tthis.bindOverlay();\n\n\t\t\tthis.keyActions = {\n\t\t\t\t'13': this.onEnterKey.bind(this),\n\t\t\t\t'37': this.onLeftArrow.bind(this),\n\t\t\t\t'38': this.onUpArrow.bind(this),\n\t\t\t\t'39': this.onRightArrow.bind(this),\n\t\t\t\t'40': this.onDownArrow.bind(this),\n\t\t\t};\n\n\t\t\tdocument.addEventListener('keydown', (e) => {\n\t\t\t\tif(isElementInViewport(this.container)) {\n\t\t\t\t\te = e || window.event;\n\t\t\t\t\tif(this.keyActions[e.keyCode]) {\n\t\t\t\t\t\tthis.keyActions[e.keyCode]();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tmakeOverlay() {}\n\tupdateOverlay() {}\n\tbindOverlay() {}\n\tbindUnits() {}\n\n\tonLeftArrow() {}\n\tonRightArrow() {}\n\tonUpArrow() {}\n\tonDownArrow() {}\n\tonEnterKey() {}\n\n\taddDataPoint() {}\n\tremoveDataPoint() {}\n\n\tgetDataPoint() {}\n\tsetCurrentDataPoint() {}\n\n\tupdateDataset() {}\n\n\texport() {\n\t\tlet chartSvg = prepareForExport(this.svg);\n\t\tdownloadFile(this.title || 'Chart', [chartSvg]);\n\t}\n}\n","import BaseChart from './BaseChart';\nimport { truncateString } from '../utils/draw-utils';\nimport { legendDot } from '../utils/draw';\nimport { round } from '../utils/helpers';\nimport { getExtraWidth } from '../utils/constants';\n\nexport default class AggregationChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\n\t\tthis.config.formatTooltipY = (args.tooltipOptions || {}).formatTooltipY;\n\t\tthis.config.maxSlices = args.maxSlices || 20;\n\t\tthis.config.maxLegendPoints = args.maxLegendPoints || 20;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\t\tlet maxSlices = this.config.maxSlices;\n\t\ts.sliceTotals = [];\n\n\t\tlet allTotals = this.data.labels.map((label, i) => {\n\t\t\tlet total = 0;\n\t\t\tthis.data.datasets.map(e => {\n\t\t\t\ttotal += e.values[i];\n\t\t\t});\n\t\t\treturn [total, label];\n\t\t}).filter(d => { return d[0] >= 0; }); // keep only positive results\n\n\t\tlet totals = allTotals;\n\t\tif(allTotals.length > maxSlices) {\n\t\t\t// Prune and keep a grey area for rest as per maxSlices\n\t\t\tallTotals.sort((a, b) => { return b[0] - a[0]; });\n\n\t\t\ttotals = allTotals.slice(0, maxSlices-1);\n\t\t\tlet remaining = allTotals.slice(maxSlices-1);\n\n\t\t\tlet sumOfRemaining = 0;\n\t\t\tremaining.map(d => {sumOfRemaining += d[0];});\n\t\t\ttotals.push([sumOfRemaining, 'Rest']);\n\t\t\tthis.colors[maxSlices-1] = 'grey';\n\t\t}\n\n\t\ts.labels = [];\n\t\ttotals.map(d => {\n\t\t\ts.sliceTotals.push(round(d[0]));\n\t\t\ts.labels.push(d[1]);\n\t\t});\n\n\t\ts.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0);\n\n\t\tthis.center = {\n\t\t\tx: this.width / 2,\n\t\t\ty: this.height / 2\n\t\t};\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.state;\n\t\tthis.legendArea.textContent = '';\n\t\tthis.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);\n\n\t\tlet count = 0;\n\t\tlet y = 0;\n\t\tthis.legendTotals.map((d, i) => {\n\t\t\tlet barWidth = 150;\n\t\t\tlet divisor = Math.floor(\n\t\t\t\t(this.width - getExtraWidth(this.measures))/barWidth\n\t\t\t);\n\t\t\tif (this.legendTotals.length < divisor) {\n\t\t\t\tbarWidth = this.width/this.legendTotals.length;\n\t\t\t}\n\t\t\tif(count > divisor) {\n\t\t\t\tcount = 0;\n\t\t\t\ty += 20;\n\t\t\t}\n\t\t\tlet x = barWidth * count + 5;\n\t\t\tlet label = this.config.truncateLegends ? truncateString(s.labels[i], barWidth/10) : s.labels[i];\n\t\t\tlet formatted = this.config.formatTooltipY ? this.config.formatTooltipY(d) : d;\n\t\t\tlet dot = legendDot(\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\t5,\n\t\t\t\tthis.colors[i],\n\t\t\t\t`${label}: ${formatted}`,\n\t\t\t\tfalse\n\t\t\t);\n\t\t\tthis.legendArea.appendChild(dot);\n\t\t\tcount++;\n\t\t});\n\t}\n}\n","import AggregationChart from './AggregationChart';\nimport { getOffset } from '../utils/dom';\nimport { getComponent } from '../objects/ChartComponents';\nimport { PERCENTAGE_BAR_DEFAULT_HEIGHT, PERCENTAGE_BAR_DEFAULT_DEPTH } from '../utils/constants';\n\nexport default class PercentageChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'percentage';\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.barOptions = options.barOptions || {};\n\n\t\tlet b = this.barOptions;\n\t\tb.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT;\n\t\tb.depth = b.depth || PERCENTAGE_BAR_DEFAULT_DEPTH;\n\n\t\tm.paddings.right = 30;\n\t\tm.legendHeight = 60;\n\t\tm.baseHeight = (b.height + b.depth * 0.5) * 8;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'percentageBars',\n\t\t\t\t{\n\t\t\t\t\tbarHeight: this.barOptions.height,\n\t\t\t\t\tbarDepth: this.barOptions.depth,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xPositions,\n\t\t\t\t\t\twidths: s.widths,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\n\t\ts.xPositions = [];\n\t\ts.widths = [];\n\n\t\tlet xPos = 0;\n\t\ts.sliceTotals.map((value) => {\n\t\t\tlet width = this.width * value / s.grandTotal;\n\t\t\ts.widths.push(width);\n\t\t\ts.xPositions.push(xPos);\n\t\t\txPos += width;\n\t\t});\n\t}\n\n\tmakeDataByIndex() { }\n\n\tbindTooltip() {\n\t\tlet s = this.state;\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet bars = this.components.get('percentageBars').store;\n\t\t\tlet bar = e.target;\n\t\t\tif(bars.includes(bar)) {\n\n\t\t\t\tlet i = bars.indexOf(bar);\n\t\t\t\tlet gOff = getOffset(this.container), pOff = getOffset(bar);\n\n\t\t\t\tlet x = pOff.left - gOff.left + parseInt(bar.getAttribute('width'))/2;\n\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\tlet title = (this.formattedLabels && this.formattedLabels.length>0\n\t\t\t\t\t? this.formattedLabels[i] : this.state.labels[i]) + ': ';\n\t\t\t\tlet fraction = s.sliceTotals[i]/s.grandTotal;\n\n\t\t\t\tthis.tip.setValues(x, y, {name: title, value: (fraction*100).toFixed(1) + \"%\"});\n\t\t\t\tthis.tip.showTip();\n\t\t\t}\n\t\t});\n\t}\n}\n","import AggregationChart from './AggregationChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset } from '../utils/dom';\nimport { getPositionByAngle } from '../utils/helpers';\nimport { makeArcPathStr, makeCircleStr } from '../utils/draw';\nimport { lightenDarkenColor } from '../utils/colors';\nimport { transform } from '../utils/animation';\nimport { FULL_ANGLE } from '../utils/constants';\n\nexport default class PieChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'pie';\n\t\tthis.initTimeout = 0;\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\t\tthis.mouseMove = this.mouseMove.bind(this);\n\t\tthis.mouseLeave = this.mouseLeave.bind(this);\n\n\t\tthis.hoverRadio = args.hoverRadio || 0.1;\n\t\tthis.config.startAngle = args.startAngle || 0;\n\n\t\tthis.clockWise = args.clockWise || false;\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\t\tthis.radius = (this.height > this.width ? this.center.x : this.center.y);\n\n\t\tconst { radius, clockWise } = this;\n\n\t\tconst prevSlicesProperties = s.slicesProperties || [];\n\t\ts.sliceStrings = [];\n\t\ts.slicesProperties = [];\n\t\tlet curAngle = 180 - this.config.startAngle;\n\t\ts.sliceTotals.map((total, i) => {\n\t\t\tconst startAngle = curAngle;\n\t\t\tconst originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;\n\t\t\tconst largeArc = originDiffAngle > 180 ? 1: 0;\n\t\t\tconst diffAngle = clockWise ? -originDiffAngle : originDiffAngle;\n\t\t\tconst endAngle = curAngle = curAngle + diffAngle;\n\t\t\tconst startPosition = getPositionByAngle(startAngle, radius);\n\t\t\tconst endPosition = getPositionByAngle(endAngle, radius);\n\n\t\t\tconst prevProperty = this.init && prevSlicesProperties[i];\n\n\t\t\tlet curStart,curEnd;\n\t\t\tif(this.init) {\n\t\t\t\tcurStart = prevProperty ? prevProperty.startPosition : startPosition;\n\t\t\t\tcurEnd = prevProperty ? prevProperty.endPosition : startPosition;\n\t\t\t} else {\n\t\t\t\tcurStart = startPosition;\n\t\t\t\tcurEnd = endPosition;\n\t\t\t}\n\t\t\tconst curPath =\n\t\t\t\toriginDiffAngle === 360\n\t\t\t\t\t? makeCircleStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc)\n\t\t\t\t\t: makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc);\n\n\t\t\ts.sliceStrings.push(curPath);\n\t\t\ts.slicesProperties.push({\n\t\t\t\tstartPosition,\n\t\t\t\tendPosition,\n\t\t\t\tvalue: total,\n\t\t\t\ttotal: s.grandTotal,\n\t\t\t\tstartAngle,\n\t\t\t\tendAngle,\n\t\t\t\tangle: diffAngle\n\t\t\t});\n\n\t\t});\n\t\tthis.init = 0;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'pieSlices',\n\t\t\t\t{ },\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsliceStrings: s.sliceStrings,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalTranslateByAngle(property){\n\t\tconst{radius,hoverRadio} = this;\n\t\tconst position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);\n\t\treturn `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;\n\t}\n\n\thoverSlice(path,i,flag,e){\n\t\tif(!path) return;\n\t\tconst color = this.colors[i];\n\t\tif(flag) {\n\t\t\ttransform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));\n\t\t\tpath.style.fill = lightenDarkenColor(color, 50);\n\t\t\tlet g_off = getOffset(this.svg);\n\t\t\tlet x = e.pageX - g_off.left + 10;\n\t\t\tlet y = e.pageY - g_off.top - 10;\n\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t\t? this.formatted_labels[i] : this.state.labels[i]) + ': ';\n\t\t\tlet percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);\n\t\t\tthis.tip.setValues(x, y, {name: title, value: percent + \"%\"});\n\t\t\tthis.tip.showTip();\n\t\t} else {\n\t\t\ttransform(path,'translate3d(0,0,0)');\n\t\t\tthis.tip.hideTip();\n\t\t\tpath.style.fill = color;\n\t\t}\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', this.mouseMove);\n\t\tthis.container.addEventListener('mouseleave', this.mouseLeave);\n\t}\n\n\tmouseMove(e){\n\t\tconst target = e.target;\n\t\tlet slices = this.components.get('pieSlices').store;\n\t\tlet prevIndex = this.curActiveSliceIndex;\n\t\tlet prevAcitve = this.curActiveSlice;\n\t\tif(slices.includes(target)) {\n\t\t\tlet i = slices.indexOf(target);\n\t\t\tthis.hoverSlice(prevAcitve, prevIndex,false);\n\t\t\tthis.curActiveSlice = target;\n\t\t\tthis.curActiveSliceIndex = i;\n\t\t\tthis.hoverSlice(target, i, true, e);\n\t\t} else {\n\t\t\tthis.mouseLeave();\n\t\t}\n\t}\n\n\tmouseLeave(){\n\t\tthis.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);\n\t}\n}\n","import BaseChart from './BaseChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { makeText, heatSquare } from '../utils/draw';\nimport { DAY_NAMES_SHORT, addDays, areInSameMonth, getLastDateInMonth, setDayToSunday, getYyyyMmDd, getWeeksBetween, getMonthName, clone,\n\tNO_OF_MILLIS, NO_OF_YEAR_MONTHS, NO_OF_DAYS_IN_WEEK } from '../utils/date-utils';\nimport { calcDistribution, getMaxCheckpoint } from '../utils/intervals';\nimport { getExtraHeight, getExtraWidth, HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE,\n\tHEATMAP_GUTTER_SIZE } from '../utils/constants';\n\nconst COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;\nconst ROW_HEIGHT = COL_WIDTH;\n// const DAY_INCR = 1;\n\nexport default class Heatmap extends BaseChart {\n\tconstructor(parent, options) {\n\t\tsuper(parent, options);\n\t\tthis.type = 'heatmap';\n\n\t\tthis.countLabel = options.countLabel || '';\n\n\t\tlet validStarts = ['Sunday', 'Monday'];\n\t\tlet startSubDomain = validStarts.includes(options.startSubDomain)\n\t\t\t? options.startSubDomain : 'Sunday';\n\t\tthis.startSubDomainIndex = validStarts.indexOf(startSubDomain);\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.discreteDomains = options.discreteDomains === 0 ? 0 : 1;\n\n\t\tm.paddings.top = ROW_HEIGHT * 3;\n\t\tm.paddings.bottom = 0;\n\t\tm.legendHeight = ROW_HEIGHT * 2;\n\t\tm.baseHeight = ROW_HEIGHT * NO_OF_DAYS_IN_WEEK\n\t\t\t+ getExtraHeight(m);\n\n\t\tlet d = this.data;\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tthis.independentWidth = (getWeeksBetween(d.start, d.end)\n\t\t\t+ spacing) * COL_WIDTH + getExtraWidth(m);\n\t}\n\n\tupdateWidth() {\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tlet noOfWeeks = this.state.noOfWeeks ? this.state.noOfWeeks : 52;\n\t\tthis.baseWidth = (noOfWeeks + spacing) * COL_WIDTH\n\t\t\t+ getExtraWidth(this.measures);\n\t}\n\n\tprepareData(data=this.data) {\n\t\tif(data.start && data.end && data.start > data.end) {\n\t\t\tthrow new Error('Start date cannot be greater than end date.');\n\t\t}\n\n\t\tif(!data.start) {\n\t\t\tdata.start = new Date();\n\t\t\tdata.start.setFullYear( data.start.getFullYear() - 1 );\n\t\t}\n\t\tif(!data.end) { data.end = new Date(); }\n\t\tdata.dataPoints = data.dataPoints || {};\n\n\t\tif(parseInt(Object.keys(data.dataPoints)[0]) > 100000) {\n\t\t\tlet points = {};\n\t\t\tObject.keys(data.dataPoints).forEach(timestampSec => {\n\t\t\t\tlet date = new Date(timestampSec * NO_OF_MILLIS);\n\t\t\t\tpoints[getYyyyMmDd(date)] = data.dataPoints[timestampSec];\n\t\t\t});\n\t\t\tdata.dataPoints = points;\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\n\t\ts.start = clone(this.data.start);\n\t\ts.end = clone(this.data.end);\n\n\t\ts.firstWeekStart = clone(s.start);\n\t\ts.noOfWeeks = getWeeksBetween(s.start, s.end);\n\t\ts.distribution = calcDistribution(\n\t\t\tObject.values(this.data.dataPoints), HEATMAP_DISTRIBUTION_SIZE);\n\n\t\ts.domainConfigs = this.getDomains();\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\t\tlet lessCol = this.discreteDomains ? 0 : 1;\n\n\t\tlet componentConfigs = s.domainConfigs.map((config, i) => [\n\t\t\t'heatDomain',\n\t\t\t{\n\t\t\t\tindex: config.index,\n\t\t\t\tcolWidth: COL_WIDTH,\n\t\t\t\trowHeight: ROW_HEIGHT,\n\t\t\t\tsquareSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\tradius: this.rawChartArgs.radius || 0,\n\t\t\t\txTranslate: s.domainConfigs\n\t\t\t\t\t.filter((config, j) => j < i)\n\t\t\t\t\t.map(config => config.cols.length - lessCol)\n\t\t\t\t\t.reduce((a, b) => a + b, 0)\n\t\t\t\t\t* COL_WIDTH\n\t\t\t},\n\t\t\tfunction() {\n\t\t\t\treturn s.domainConfigs[i];\n\t\t\t}.bind(this)\n\n\t\t]);\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map((args, i) => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0] + '-' + i, component];\n\t\t\t})\n\t\t);\n\n\t\tlet y = 0;\n\t\tDAY_NAMES_SHORT.forEach((dayName, i) => {\n\t\t\tif([1, 3, 5].includes(i)) {\n\t\t\t\tlet dayText = makeText('subdomain-name', -COL_WIDTH/2, y, dayName,\n\t\t\t\t\t{\n\t\t\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\t\t\tdy: 8,\n\t\t\t\t\t\ttextAnchor: 'end'\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tthis.drawArea.appendChild(dayText);\n\t\t\t}\n\t\t\ty += ROW_HEIGHT;\n\t\t});\n\t}\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\n\t\tthis.data = this.prepareData(data);\n\t\tthis.draw();\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tthis.components.forEach(comp => {\n\t\t\t\tlet daySquares = comp.store;\n\t\t\t\tlet daySquare = e.target;\n\t\t\t\tif(daySquares.includes(daySquare)) {\n\n\t\t\t\t\tlet count = daySquare.getAttribute('data-value');\n\t\t\t\t\tlet dateParts = daySquare.getAttribute('data-date').split('-');\n\n\t\t\t\t\tlet month = getMonthName(parseInt(dateParts[1])-1, true);\n\n\t\t\t\t\tlet gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect();\n\n\t\t\t\t\tlet width = parseInt(e.target.getAttribute('width'));\n\t\t\t\t\tlet x = pOff.left - gOff.left + width/2;\n\t\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\t\tlet value = count + ' ' + this.countLabel;\n\t\t\t\t\tlet name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2];\n\n\t\t\t\t\tthis.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);\n\t\t\t\t\tthis.tip.showTip();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\trenderLegend() {\n\t\tthis.legendArea.textContent = '';\n\t\tlet x = 0;\n\t\tlet y = ROW_HEIGHT;\n\t\tlet radius = this.rawChartArgs.radius || 0;\n\n\t\tlet lessText = makeText('subdomain-name', x, y, 'Less',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tx = (COL_WIDTH * 2) + COL_WIDTH/2;\n\t\tthis.legendArea.appendChild(lessText);\n\n\t\tthis.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map((color, i) => {\n\t\t\tconst square = heatSquare('heatmap-legend-unit', x + (COL_WIDTH + 3) * i,\n\t\t\t\ty, HEATMAP_SQUARE_SIZE, radius, color);\n\t\t\tthis.legendArea.appendChild(square);\n\t\t});\n\n\t\tlet moreTextX = x + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH/4;\n\t\tlet moreText = makeText('subdomain-name', moreTextX, y, 'More',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tthis.legendArea.appendChild(moreText);\n\t}\n\n\tgetDomains() {\n\t\tlet s = this.state;\n\t\tconst [startMonth, startYear] = [s.start.getMonth(), s.start.getFullYear()];\n\t\tconst [endMonth, endYear] = [s.end.getMonth(), s.end.getFullYear()];\n\n\t\tconst noOfMonths = (endMonth - startMonth + 1) + (endYear - startYear) * 12;\n\n\t\tlet domainConfigs = [];\n\n\t\tlet startOfMonth = clone(s.start);\n\t\tfor(var i = 0; i < noOfMonths; i++) {\n\t\t\tlet endDate = s.end;\n\t\t\tif(!areInSameMonth(startOfMonth, s.end)) {\n\t\t\t\tlet [month, year] = [startOfMonth.getMonth(), startOfMonth.getFullYear()];\n\t\t\t\tendDate = getLastDateInMonth(month, year);\n\t\t\t}\n\t\t\tdomainConfigs.push(this.getDomainConfig(startOfMonth, endDate));\n\n\t\t\taddDays(endDate, 1);\n\t\t\tstartOfMonth = endDate;\n\t\t}\n\n\t\treturn domainConfigs;\n\t}\n\n\tgetDomainConfig(startDate, endDate='') {\n\t\tlet [month, year] = [startDate.getMonth(), startDate.getFullYear()];\n\t\tlet startOfWeek = setDayToSunday(startDate); // TODO: Monday as well\n\t\tendDate = clone(endDate) || getLastDateInMonth(month, year);\n\n\t\tlet domainConfig = {\n\t\t\tindex: month,\n\t\t\tcols: []\n\t\t};\n\n\t\taddDays(endDate, 1);\n\t\tlet noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate);\n\n\t\tlet cols = [], col;\n\t\tfor(var i = 0; i < noOfMonthWeeks; i++) {\n\t\t\tcol = this.getCol(startOfWeek, month);\n\t\t\tcols.push(col);\n\n\t\t\tstartOfWeek = new Date(col[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd);\n\t\t\taddDays(startOfWeek, 1);\n\t\t}\n\n\t\tif(col[NO_OF_DAYS_IN_WEEK - 1].dataValue !== undefined) {\n\t\t\taddDays(startOfWeek, 1);\n\t\t\tcols.push(this.getCol(startOfWeek, month, true));\n\t\t}\n\n\t\tdomainConfig.cols = cols;\n\n\t\treturn domainConfig;\n\t}\n\n\tgetCol(startDate, month, empty = false) {\n\t\tlet s = this.state;\n\n\t\t// startDate is the start of week\n\t\tlet currentDate = clone(startDate);\n\t\tlet col = [];\n\n\t\tfor(var i = 0; i < NO_OF_DAYS_IN_WEEK; i++, addDays(currentDate, 1)) {\n\t\t\tlet config = {};\n\n\t\t\t// Non-generic adjustment for entire heatmap, needs state\n\t\t\tlet currentDateWithinData = currentDate >= s.start && currentDate <= s.end;\n\n\t\t\tif(empty || currentDate.getMonth() !== month || !currentDateWithinData) {\n\t\t\t\tconfig.yyyyMmDd = getYyyyMmDd(currentDate);\n\t\t\t} else {\n\t\t\t\tconfig = this.getSubDomainConfig(currentDate);\n\t\t\t}\n\t\t\tcol.push(config);\n\t\t}\n\n\t\treturn col;\n\t}\n\n\tgetSubDomainConfig(date) {\n\t\tlet yyyyMmDd = getYyyyMmDd(date);\n\t\tlet dataValue = this.data.dataPoints[yyyyMmDd];\n\t\tlet config = {\n\t\t\tyyyyMmDd: yyyyMmDd,\n\t\t\tdataValue: dataValue || 0,\n\t\t\tfill: this.colors[getMaxCheckpoint(dataValue, this.state.distribution)]\n\t\t};\n\t\treturn config;\n\t}\n}\n","import BaseChart from './BaseChart';\nimport { dataPrep, zeroDataPrep, getShortenedLabels } from '../utils/axis-chart-utils';\nimport { AXIS_LEGEND_BAR_SIZE } from '../utils/constants';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset, fire } from '../utils/dom';\nimport { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale, getClosestInArray } from '../utils/intervals';\nimport { floatTwo } from '../utils/helpers';\nimport { makeOverlay, updateOverlay, legendBar } from '../utils/draw';\nimport { getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO,\n\tLINE_CHART_DOT_SIZE } from '../utils/constants';\n\nexport default class AxisChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\n\t\tthis.barOptions = args.barOptions || {};\n\t\tthis.lineOptions = args.lineOptions || {};\n\n\t\tthis.type = args.type || 'line';\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures() {\n\t\tif(this.data.datasets.length <= 1) {\n\t\t\tthis.config.showLegend = 0;\n\t\t\tthis.measures.paddings.bottom = 30;\n\t\t}\n\t}\n\n\tconfigure(options) {\n\t\tsuper.configure(options);\n\n\t\toptions.axisOptions = options.axisOptions || {};\n\t\toptions.tooltipOptions = options.tooltipOptions || {};\n\n\t\tthis.config.xAxisMode = options.axisOptions.xAxisMode || 'span';\n\t\tthis.config.yAxisMode = options.axisOptions.yAxisMode || 'span';\n\t\tthis.config.xIsSeries = options.axisOptions.xIsSeries || 0;\n\t\tthis.config.shortenYAxisNumbers = options.axisOptions.shortenYAxisNumbers || 0;\n\n\t\tthis.config.formatTooltipX = options.tooltipOptions.formatTooltipX;\n\t\tthis.config.formatTooltipY = options.tooltipOptions.formatTooltipY;\n\n\t\tthis.config.valuesOverPoints = options.valuesOverPoints;\n\t}\n\n\tprepareData(data=this.data) {\n\t\treturn dataPrep(data, this.type);\n\t}\n\n\tprepareFirstData(data=this.data) {\n\t\treturn zeroDataPrep(data);\n\t}\n\n\tcalc(onlyWidthChange = false) {\n\t\tthis.calcXPositions();\n\t\tif(!onlyWidthChange) {\n\t\t\tthis.calcYAxisParameters(this.getAllYValues(), this.type === 'line');\n\t\t}\n\t\tthis.makeDataByIndex();\n\t}\n\n\tcalcXPositions() {\n\t\tlet s = this.state;\n\t\tlet labels = this.data.labels;\n\t\ts.datasetLength = labels.length;\n\n\t\ts.unitWidth = this.width/(s.datasetLength);\n\t\t// Default, as per bar, and mixed. Only line will be a special case\n\t\ts.xOffset = s.unitWidth/2;\n\n\t\t// // For a pure Line Chart\n\t\t// s.unitWidth = this.width/(s.datasetLength - 1);\n\t\t// s.xOffset = 0;\n\n\t\ts.xAxis = {\n\t\t\tlabels: labels,\n\t\t\tpositions: labels.map((d, i) =>\n\t\t\t\tfloatTwo(s.xOffset + i * s.unitWidth)\n\t\t\t)\n\t\t};\n\t}\n\n\tcalcYAxisParameters(dataValues, withMinimum = 'false') {\n\t\tconst yPts = calcChartIntervals(dataValues, withMinimum);\n\t\tconst scaleMultiplier = this.height / getValueRange(yPts);\n\t\tconst intervalHeight = getIntervalSize(yPts) * scaleMultiplier;\n\t\tconst zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight);\n\n\t\tthis.state.yAxis = {\n\t\t\tlabels: yPts,\n\t\t\tpositions: yPts.map(d => zeroLine - d * scaleMultiplier),\n\t\t\tscaleMultiplier: scaleMultiplier,\n\t\t\tzeroLine: zeroLine,\n\t\t};\n\n\t\t// Dependent if above changes\n\t\tthis.calcDatasetPoints();\n\t\tthis.calcYExtremes();\n\t\tthis.calcYRegions();\n\t}\n\n\tcalcDatasetPoints() {\n\t\tlet s = this.state;\n\t\tlet scaleAll = values => values.map(val => scale(val, s.yAxis));\n\n\t\ts.datasets = this.data.datasets.map((d, i) => {\n\t\t\tlet values = d.values;\n\t\t\tlet cumulativeYs = d.cumulativeYs || [];\n\t\t\treturn {\n\t\t\t\tname: d.name && d.name.replace(/<|>|&/g, (char) => char == '&' ? '&' : char == '<' ? '<' : '>'),\n\t\t\t\tindex: i,\n\t\t\t\tchartType: d.chartType,\n\n\t\t\t\tvalues: values,\n\t\t\t\tyPositions: scaleAll(values),\n\n\t\t\t\tcumulativeYs: cumulativeYs,\n\t\t\t\tcumulativeYPos: scaleAll(cumulativeYs),\n\t\t\t};\n\t\t});\n\t}\n\n\tcalcYExtremes() {\n\t\tlet s = this.state;\n\t\tif(this.barOptions.stacked) {\n\t\t\ts.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos;\n\t\t\treturn;\n\t\t}\n\t\ts.yExtremes = new Array(s.datasetLength).fill(9999);\n\t\ts.datasets.map(d => {\n\t\t\td.yPositions.map((pos, j) => {\n\t\t\t\tif(pos < s.yExtremes[j]) {\n\t\t\t\t\ts.yExtremes[j] = pos;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tcalcYRegions() {\n\t\tlet s = this.state;\n\t\tif(this.data.yMarkers) {\n\t\t\tthis.state.yMarkers = this.data.yMarkers.map(d => {\n\t\t\t\td.position = scale(d.value, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\t// if(!d.label.includes(':')) {\n\t\t\t\t// \td.label += ': ' + d.value;\n\t\t\t\t// }\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.state.yRegions = this.data.yRegions.map(d => {\n\t\t\t\td.startPos = scale(d.start, s.yAxis);\n\t\t\t\td.endPos = scale(d.end, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t}\n\n\tgetAllYValues() {\n\t\tlet key = 'values';\n\n\t\tif(this.barOptions.stacked) {\n\t\t\tkey = 'cumulativeYs';\n\t\t\tlet cumulative = new Array(this.state.datasetLength).fill(0);\n\t\t\tthis.data.datasets.map((d, i) => {\n\t\t\t\tlet values = this.data.datasets[i].values;\n\t\t\t\td[key] = cumulative = cumulative.map((c, i) => c + values[i]);\n\t\t\t});\n\t\t}\n\n\t\tlet allValueLists = this.data.datasets.map(d => d[key]);\n\t\tif(this.data.yMarkers) {\n\t\t\tallValueLists.push(this.data.yMarkers.map(d => d.value));\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.data.yRegions.map(d => {\n\t\t\t\tallValueLists.push([d.end, d.start]);\n\t\t\t});\n\t\t}\n\n\t\treturn [].concat(...allValueLists);\n\t}\n\n\tsetupComponents() {\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'yAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.yAxisMode,\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tshortenNumbers: this.config.shortenYAxisNumbers\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'xAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.xAxisMode,\n\t\t\t\t\theight: this.height,\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\ts.xAxis.calcLabels = getShortenedLabels(this.width,\n\t\t\t\t\t\ts.xAxis.labels, this.config.xIsSeries);\n\n\t\t\t\t\treturn s.xAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'yRegions',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yRegions;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\t\t];\n\n\t\tlet barDatasets = this.state.datasets.filter(d => d.chartType === 'bar');\n\t\tlet lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');\n\n\t\tlet barsConfigs = barDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'barGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tstacked: this.barOptions.stacked,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t\tminHeight: this.height * MIN_BAR_PERCENT_HEIGHT,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet stacked = this.barOptions.stacked;\n\n\t\t\t\t\tlet spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO;\n\t\t\t\t\tlet barsWidth = s.unitWidth * (1 - spaceRatio);\n\t\t\t\t\tlet barWidth = barsWidth/(stacked ? 1 : barDatasets.length);\n\n\t\t\t\t\tlet xPositions = s.xAxis.positions.map(x => x - barsWidth/2);\n\t\t\t\t\tif(!stacked) {\n\t\t\t\t\t\txPositions = xPositions.map(p => p + barWidth * index);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet labels = new Array(s.datasetLength).fill('');\n\t\t\t\t\tif(this.config.valuesOverPoints) {\n\t\t\t\t\t\tif(stacked && d.index === s.datasets.length - 1) {\n\t\t\t\t\t\t\tlabels = d.cumulativeYs;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlabels = d.values;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet offsets = new Array(s.datasetLength).fill(0);\n\t\t\t\t\tif(stacked) {\n\t\t\t\t\t\toffsets = d.yPositions.map((y, j) => y - d.cumulativeYPos[j]);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: xPositions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\t\t\t\t\t\toffsets: offsets,\n\t\t\t\t\t\t// values: d.values,\n\t\t\t\t\t\tlabels: labels,\n\n\t\t\t\t\t\tzeroLine: s.yAxis.zeroLine,\n\t\t\t\t\t\tbarsWidth: barsWidth,\n\t\t\t\t\t\tbarWidth: barWidth,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet lineConfigs = lineDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'lineGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tsvgDefs: this.svgDefs,\n\t\t\t\t\theatline: this.lineOptions.heatline,\n\t\t\t\t\tregionFill: this.lineOptions.regionFill,\n\t\t\t\t\tspline: this.lineOptions.spline,\n\t\t\t\t\thideDots: this.lineOptions.hideDots,\n\t\t\t\t\thideLine: this.lineOptions.hideLine,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet minLine = s.yAxis.positions[0] < s.yAxis.zeroLine\n\t\t\t\t\t\t? s.yAxis.positions[0] : s.yAxis.zeroLine;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xAxis.positions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\n\t\t\t\t\t\tvalues: d.values,\n\n\t\t\t\t\t\tzeroLine: minLine,\n\t\t\t\t\t\tradius: this.lineOptions.dotSize || LINE_CHART_DOT_SIZE,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet markerConfigs = [\n\t\t\t[\n\t\t\t\t'yMarkers',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yMarkers;\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tcomponentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);\n\n\t\tlet optionals = ['yMarkers', 'yRegions'];\n\t\tthis.dataUnitComponents = [];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.filter(args => !optionals.includes(args[0]) || this.state[args[0]])\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\tif(args[0].includes('lineGraph') || args[0].includes('barGraph')) {\n\t\t\t\t\tthis.dataUnitComponents.push(component);\n\t\t\t\t}\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tmakeDataByIndex() {\n\t\tthis.dataByIndex = {};\n\n\t\tlet s = this.state;\n\t\tlet formatX = this.config.formatTooltipX;\n\t\tlet formatY = this.config.formatTooltipY;\n\t\tlet titles = s.xAxis.labels;\n\n\t\ttitles.map((label, index) => {\n\t\t\tlet values = this.state.datasets.map((set, i) => {\n\t\t\t\tlet value = set.values[index];\n\t\t\t\treturn {\n\t\t\t\t\ttitle: set.name,\n\t\t\t\t\tvalue: value,\n\t\t\t\t\tyPos: set.yPositions[index],\n\t\t\t\t\tcolor: this.colors[i],\n\t\t\t\t\tformatted: formatY ? formatY(value) : value,\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tthis.dataByIndex[index] = {\n\t\t\t\tlabel: label,\n\t\t\t\tformattedLabel: formatX ? formatX(label) : label,\n\t\t\t\txPos: s.xAxis.positions[index],\n\t\t\t\tvalues: values,\n\t\t\t\tyExtreme: s.yExtremes[index],\n\t\t\t};\n\t\t});\n\t}\n\n\tbindTooltip() {\n\t\t// NOTE: could be in tooltip itself, as it is a given functionality for its parent\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet m = this.measures;\n\t\t\tlet o = getOffset(this.container);\n\t\t\tlet relX = e.pageX - o.left - getLeftOffset(m);\n\t\t\tlet relY = e.pageY - o.top;\n\n\t\t\tif(relY < this.height + getTopOffset(m)\n\t\t\t\t&& relY > getTopOffset(m)) {\n\t\t\t\tthis.mapTooltipXPosition(relX);\n\t\t\t} else {\n\t\t\t\tthis.tip.hideTip();\n\t\t\t}\n\t\t});\n\t}\n\n\tmapTooltipXPosition(relX) {\n\t\tlet s = this.state;\n\t\tif(!s.yExtremes) return;\n\n\t\tlet index = getClosestInArray(relX, s.xAxis.positions, true);\n\t\tif (index >= 0) {\n\t\t\tlet dbi = this.dataByIndex[index];\n\n\t\t\tthis.tip.setValues(\n\t\t\t\tdbi.xPos + this.tip.offset.x,\n\t\t\t\tdbi.yExtreme + this.tip.offset.y,\n\t\t\t\t{name: dbi.formattedLabel, value: ''},\n\t\t\t\tdbi.values,\n\t\t\t\tindex\n\t\t\t);\n\n\t\t\tthis.tip.showTip();\n\t\t}\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.data;\n\t\tif(s.datasets.length > 1) {\n\t\t\tthis.legendArea.textContent = '';\n\t\t\ts.datasets.map((d, i) => {\n\t\t\t\tlet barWidth = AXIS_LEGEND_BAR_SIZE;\n\t\t\t\t// let rightEndPoint = this.baseWidth - this.measures.margins.left - this.measures.margins.right;\n\t\t\t\t// let multiplier = s.datasets.length - i;\n\t\t\t\tlet rect = legendBar(\n\t\t\t\t\t// rightEndPoint - multiplier * barWidth,\t// To right align\n\t\t\t\t\tbarWidth * i,\n\t\t\t\t\t'0',\n\t\t\t\t\tbarWidth,\n\t\t\t\t\tthis.colors[i],\n\t\t\t\t\td.name,\n\t\t\t\t\tthis.config.truncateLegends);\n\t\t\t\tthis.legendArea.appendChild(rect);\n\t\t\t});\n\t\t}\n\t}\n\n\n\n\t// Overlay\n\tmakeOverlay() {\n\t\tif(this.init) {\n\t\t\tthis.init = 0;\n\t\t\treturn;\n\t\t}\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\n\t\tthis.overlayGuides = this.dataUnitComponents.map(c => {\n\t\t\treturn {\n\t\t\t\ttype: c.unitType,\n\t\t\t\toverlay: undefined,\n\t\t\t\tunits: c.units,\n\t\t\t};\n\t\t});\n\n\t\tif(this.state.currentIndex === undefined) {\n\t\t\tthis.state.currentIndex = this.state.datasetLength - 1;\n\t\t}\n\n\t\t// Render overlays\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\n\t\t\td.overlay = makeOverlay[d.type](currentUnit);\n\t\t\tthis.drawArea.appendChild(d.overlay);\n\t\t});\n\t}\n\n\tupdateOverlayGuides() {\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\t}\n\n\tbindOverlay() {\n\t\tthis.parent.addEventListener('data-select', () => {\n\t\t\tthis.updateOverlay();\n\t\t});\n\t}\n\n\tbindUnits() {\n\t\tthis.dataUnitComponents.map(c => {\n\t\t\tc.units.map(unit => {\n\t\t\t\tunit.addEventListener('click', () => {\n\t\t\t\t\tlet index = unit.getAttribute('data-point-index');\n\t\t\t\t\tthis.setCurrentDataPoint(index);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\t// Note: Doesn't work as tooltip is absolutely positioned\n\t\tthis.tip.container.addEventListener('click', () => {\n\t\t\tlet index = this.tip.container.getAttribute('data-point-index');\n\t\t\tthis.setCurrentDataPoint(index);\n\t\t});\n\t}\n\n\tupdateOverlay() {\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\t\t\tupdateOverlay[d.type](currentUnit, d.overlay);\n\t\t});\n\t}\n\n\tonLeftArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex - 1);\n\t}\n\n\tonRightArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex + 1);\n\t}\n\n\tgetDataPoint(index=this.state.currentIndex) {\n\t\tlet s = this.state;\n\t\tlet data_point = {\n\t\t\tindex: index,\n\t\t\tlabel: s.xAxis.labels[index],\n\t\t\tvalues: s.datasets.map(d => d.values[index])\n\t\t};\n\t\treturn data_point;\n\t}\n\n\tsetCurrentDataPoint(index) {\n\t\tlet s = this.state;\n\t\tindex = parseInt(index);\n\t\tif(index < 0) index = 0;\n\t\tif(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1;\n\t\tif(index === s.currentIndex) return;\n\t\ts.currentIndex = index;\n\t\tfire(this.parent, \"data-select\", this.getDataPoint());\n\t}\n\n\n\n\t// API\n\taddDataPoint(label, datasetValues, index=this.state.datasetLength) {\n\t\tsuper.addDataPoint(label, datasetValues, index);\n\t\tthis.data.labels.splice(index, 0, label);\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\td.values.splice(index, 0, datasetValues[i]);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tremoveDataPoint(index = this.state.datasetLength-1) {\n\t\tif (this.data.labels.length <= 1) {\n\t\t\treturn;\n\t\t}\n\t\tsuper.removeDataPoint(index);\n\t\tthis.data.labels.splice(index, 1);\n\t\tthis.data.datasets.map(d => {\n\t\t\td.values.splice(index, 1);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tupdateDataset(datasetValues, index=0) {\n\t\tthis.data.datasets[index].values = datasetValues;\n\t\tthis.update(this.data);\n\t}\n\t// addDataset(dataset, index) {}\n\t// removeDataset(index = 0) {}\n\n\tupdateDatasets(datasets) {\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\tif(datasets[i]) {\n\t\t\t\td.values = datasets[i];\n\t\t\t}\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\t// updateDataPoint(dataPoint, index = 0) {}\n\t// addDataPoint(dataPoint, index = 0) {}\n\t// removeDataPoint(index = 0) {}\n}\n","import AggregationChart from './AggregationChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset } from '../utils/dom';\nimport { getPositionByAngle } from '../utils/helpers';\nimport { makeArcStrokePathStr, makeStrokeCircleStr } from '../utils/draw';\nimport { lightenDarkenColor } from '../utils/colors';\nimport { transform } from '../utils/animation';\nimport { FULL_ANGLE } from '../utils/constants';\n\nexport default class DonutChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'donut';\n\t\tthis.initTimeout = 0;\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\t\tthis.mouseMove = this.mouseMove.bind(this);\n\t\tthis.mouseLeave = this.mouseLeave.bind(this);\n\n\t\tthis.hoverRadio = args.hoverRadio || 0.1;\n\t\tthis.config.startAngle = args.startAngle || 0;\n\n\t\tthis.clockWise = args.clockWise || false;\n\t\tthis.strokeWidth = args.strokeWidth || 30;\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\t\tthis.radius =\n\t\t\tthis.height > this.width\n\t\t\t\t? this.center.x - this.strokeWidth / 2\n\t\t\t\t: this.center.y - this.strokeWidth / 2;\n\n\t\tconst { radius, clockWise } = this;\n\n\t\tconst prevSlicesProperties = s.slicesProperties || [];\n\t\ts.sliceStrings = [];\n\t\ts.slicesProperties = [];\n\t\tlet curAngle = 180 - this.config.startAngle;\n\n\t\ts.sliceTotals.map((total, i) => {\n\t\t\tconst startAngle = curAngle;\n\t\t\tconst originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;\n\t\t\tconst largeArc = originDiffAngle > 180 ? 1: 0;\n\t\t\tconst diffAngle = clockWise ? -originDiffAngle : originDiffAngle;\n\t\t\tconst endAngle = curAngle = curAngle + diffAngle;\n\t\t\tconst startPosition = getPositionByAngle(startAngle, radius);\n\t\t\tconst endPosition = getPositionByAngle(endAngle, radius);\n\n\t\t\tconst prevProperty = this.init && prevSlicesProperties[i];\n\n\t\t\tlet curStart,curEnd;\n\t\t\tif(this.init) {\n\t\t\t\tcurStart = prevProperty ? prevProperty.startPosition : startPosition;\n\t\t\t\tcurEnd = prevProperty ? prevProperty.endPosition : startPosition;\n\t\t\t} else {\n\t\t\t\tcurStart = startPosition;\n\t\t\t\tcurEnd = endPosition;\n\t\t\t}\n\t\t\tconst curPath =\n\t\t\t\toriginDiffAngle === 360\n\t\t\t\t\t? makeStrokeCircleStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc)\n\t\t\t\t\t: makeArcStrokePathStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc);\n\n\t\t\ts.sliceStrings.push(curPath);\n\t\t\ts.slicesProperties.push({\n\t\t\t\tstartPosition,\n\t\t\t\tendPosition,\n\t\t\t\tvalue: total,\n\t\t\t\ttotal: s.grandTotal,\n\t\t\t\tstartAngle,\n\t\t\t\tendAngle,\n\t\t\t\tangle: diffAngle\n\t\t\t});\n\n\t\t});\n\t\tthis.init = 0;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'donutSlices',\n\t\t\t\t{ },\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsliceStrings: s.sliceStrings,\n\t\t\t\t\t\tcolors: this.colors,\n\t\t\t\t\t\tstrokeWidth: this.strokeWidth,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalTranslateByAngle(property){\n\t\tconst{ radius, hoverRadio } = this;\n\t\tconst position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);\n\t\treturn `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;\n\t}\n\n\thoverSlice(path,i,flag,e){\n\t\tif(!path) return;\n\t\tconst color = this.colors[i];\n\t\tif(flag) {\n\t\t\ttransform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));\n\t\t\tpath.style.stroke = lightenDarkenColor(color, 50);\n\t\t\tlet g_off = getOffset(this.svg);\n\t\t\tlet x = e.pageX - g_off.left + 10;\n\t\t\tlet y = e.pageY - g_off.top - 10;\n\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t\t? this.formatted_labels[i] : this.state.labels[i]) + ': ';\n\t\t\tlet percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);\n\t\t\tthis.tip.setValues(x, y, {name: title, value: percent + \"%\"});\n\t\t\tthis.tip.showTip();\n\t\t} else {\n\t\t\ttransform(path,'translate3d(0,0,0)');\n\t\t\tthis.tip.hideTip();\n\t\t\tpath.style.stroke = color;\n\t\t}\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', this.mouseMove);\n\t\tthis.container.addEventListener('mouseleave', this.mouseLeave);\n\t}\n\n\tmouseMove(e){\n\t\tconst target = e.target;\n\t\tlet slices = this.components.get('donutSlices').store;\n\t\tlet prevIndex = this.curActiveSliceIndex;\n\t\tlet prevAcitve = this.curActiveSlice;\n\t\tif(slices.includes(target)) {\n\t\t\tlet i = slices.indexOf(target);\n\t\t\tthis.hoverSlice(prevAcitve, prevIndex,false);\n\t\t\tthis.curActiveSlice = target;\n\t\t\tthis.curActiveSliceIndex = i;\n\t\t\tthis.hoverSlice(target, i, true, e);\n\t\t} else {\n\t\t\tthis.mouseLeave();\n\t\t}\n\t}\n\n\tmouseLeave(){\n\t\tthis.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);\n\t}\n}\n"],"names":["styleInject","css","ref","insertAt","document","head","getElementsByTagName","style","createElement","type","firstChild","insertBefore","appendChild","styleSheet","cssText","createTextNode","$","expr","con","querySelector","getOffset","element","rect","getBoundingClientRect","top","documentElement","scrollTop","body","left","scrollLeft","isHidden","el","offsetParent","isElementInViewport","bottom","window","innerHeight","clientHeight","right","innerWidth","clientWidth","getElementContentWidth","styles","getComputedStyle","padding","parseFloat","paddingLeft","paddingRight","fire","target","properties","evt","createEvent","initEvent","j","dispatchEvent","getTopOffset","m","titleHeight","margins","paddings","getLeftOffset","getExtraHeight","legendHeight","getExtraWidth","floatTwo","d","toFixed","fillArray","array","count","start","length","fillerArray","Array","Math","abs","fill","concat","getStringWidth","string","charWidth","getPositionByAngle","angle","radius","sin","ANGLE_RATIO","cos","isValidNumber","candidate","nonNegative","Number","isNaN","undefined","isFinite","round","deepClone","cloned","value","key","Date","getTime","isArray","getBarHeightAndYAttr","yTop","zeroLine","height","y","equilizeNoOfElements","array1","array2","extraCount","truncateString","txt","len","slice","shortenLargeNumber","label","number","p","floor","log10","l","shortened","pow","getSplineCurvePointsStr","xList","yList","points","i","push","line","pointA","pointB","lengthX","lengthY","sqrt","atan2","controlPoint","current","previous","next","reverse","o","PI","command","reduce","acc","point","a","cps","cpe","limitColor","r","lightenDarkenColor","color","amt","col","getColor","usePound","num","parseInt","b","g","toString","isValidColor","RGB_RE","test","createSVG","tag","createElementNS","val","parentNode","keys","map","prop","setAttribute","renderVerticalGradient","svgDefElem","gradientId","setGradientStop","gradElem","offset","opacity","makeSVGContainer","parent","className","width","makeSVGDefs","svgContainer","makeSVGGroup","transform","args","inside","makePath","pathStr","makeArcPathStr","startPosition","endPosition","center","clockWise","largeArc","arcStartX","x","arcStartY","arcEndX","arcEndY","makeCircleStr","midArc","makeArcStrokePathStr","makeStrokeCircleStr","makeGradient","lighter","gradientDef","opacities","percentageBar","depth","PERCENTAGE_BAR_DEFAULT_DEPTH","heatSquare","size","data","legendBar","LABEL_MAX_CHARS","text","FONT_SIZE","FONT_FILL","group","legendDot","makeText","content","options","fontSize","dy","textAnchor","makeVertLine","y1","y2","stroke","BASE_LINE_COLOR","LABEL_MARGIN","makeHoriLine","x1","x2","lineType","shortenNumbers","yLine","pos","mode","AXIS_TICK_LENGTH","xLine","yMarker","labelPos","labelSvg","yRegion","region","datasetBar","index","meta","minHeight","datasetDot","dot","getPaths","pointsStr","join","spline","path","heatline","gradient_id","svgDefs","paths","regionFill","gradient_id_region","translate","unit","oldCoord","newCoord","duration","old","STD_EASING","translateVertLine","newX","oldX","MARKER_LINE_ANIM_DUR","translateHoriLine","newY","oldY","animateRegion","rectGroup","newY1","newY2","oldY2","newHeight","childNodes","stroke-dasharray","getAttribute","animateBar","bar","nodeName","UNIT_ANIM_DUR","split","animateDot","cx","cy","animatePath","newXList","newYList","pathComponents","animPath","PATH_ANIM_DUR","regStartPt","regEndPt","animRegion","animatePathStr","oldPath","animateSVGElement","props","dur","easingType","oldValues","animElement","cloneNode","newElement","attributeName","animateElement","currentValue","animAttr","EASING","webkitTransform","msTransform","mozTransform","oTransform","animateSVG","elements","newElements","animElements","replaceChild","animSvg","runSMILAnimation","svgElement","elementsToAnimate","animSvgElement","removeChild","REPLACE_ALL_NEW_DUR","downloadFile","filename","blob","Blob","url","URL","createObjectURL","href","download","click","revokeObjectURL","prepareForExport","svg","clone","classList","add","styleEl","create","CSSTEXT","container","innerHTML","treatAsUtc","date","result","setMinutes","getMinutes","getTimezoneOffset","getYyyyMmDd","dd","getDate","mm","getMonth","getFullYear","getWeeksBetween","startDate","endDate","weekStartDate","setDayToSunday","ceil","getDaysBetween","NO_OF_DAYS_IN_WEEK","millisecondsPerDay","SEC_IN_DAY","NO_OF_MILLIS","areInSameMonth","getMonthName","short","monthName","MONTH_NAMES","getLastDateInMonth","month","year","newDate","day","getDay","addDays","numberOfDays","setDate","getComponent","name","constants","getData","Object","componentConfigs","filter","includes","k","config","assign","ChartComponent","normalize","mantissa","exponent","sig","exp","getChartRangeIntervals","max","min","upperBound","lowerBound","range","noOfParts","partSize","intervals","getChartIntervals","maxValue","minValue","normalMaxValue","normalMinValue","calcChartIntervals","values","getPositiveFirstIntervals","absMinValue","intervalSize","unshift","withMinimum","pseudoMaxValue","pseudoMinValue","getZeroIndex","yPts","interval","getIntervalSize","indexOf","orderedArray","getValueRange","scale","yAxis","scaleMultiplier","getClosestInArray","goal","arr","closest","prev","curr","calcDistribution","distributionSize","dataMaxValue","distributionStep","distribution","checkpoint","getMaxCheckpoint","dataPrep","labels","datasetLength","datasets","zeroArray","vals","chartType","AXIS_DATASET_CHART_TYPES","yRegions","end","zeroDataPrep","realData","zeroData","yMarkers","getShortenedLabels","chartWidth","isSeries","allowedSpace","allowedLetters","DEFAULT_CHAR_WIDTH","seriesMultiple","maxLabelLength","getChartByType","AxisChart","chartTypes","error","BASE_MEASURES","INIT_CHART_UPDATE_TIMEOUT","CHART_POST_ANIMATE_TIMEOUT","DEFAULT_AXIS_CHART_TYPE","AXIS_LEGEND_BAR_SIZE","BAR_CHART_SPACE_RATIO","MIN_BAR_PERCENT_HEIGHT","LINE_CHART_DOT_SIZE","DOT_OVERLAY_SIZE_INCR","PERCENTAGE_BAR_DEFAULT_HEIGHT","HEATMAP_DISTRIBUTION_SIZE","HEATMAP_SQUARE_SIZE","HEATMAP_GUTTER_SIZE","TOOLTIP_POINTER_TRIANGLE_HEIGHT","DEFAULT_CHART_COLORS","HEATMAP_COLORS_GREEN","DEFAULT_COLORS","FULL_ANGLE","SvgTip","colors","titleName","titleValue","listValues","titleValueFirst","setup","makeTooltip","calcPosition","this","hideTip","title","dataPointList","addEventListener","set","_this2","formatted","li","offsetWidth","offsetHeight","maxLeft","pointer","pointerOffset","valueFirst","refresh","PRESET_COLOR_MAP","exec","c","ch","makeOverlay","transformValue","overlay","updateOverlay","attributes","attr","specified","nodeValue","BaseChart","HTMLElement","Error","rawChartArgs","prepareData","prepareFirstData","validateColors","isNavigable","animate","truncateLegends","measures","JSON","parse","stringify","setMeasures","showLegend","argHeight","baseHeight","state","initTimeout","overlays","configure","validColors","forEach","warn","boundDrawFn","_this","draw","ResizeObserver","resizeObserver","observe","disconnect","removeEventListener","makeContainer","updateWidth","independentWidth","tip","bindTooltip","onlyWidthChange","init","calc","makeChartArea","setupComponents","components","drawArea","render","update","renderLegend","setupNavigation","baseWidth","titleEL","titleFontSize","legendArea","updateTipOffset","Map","make","updateNav","bindUnits","bindOverlay","keyActions","onEnterKey","bind","onLeftArrow","onUpArrow","onRightArrow","onDownArrow","e","_this4","event","keyCode","chartSvg","AggregationChart","formatTooltipY","tooltipOptions","maxSlices","maxLegendPoints","s","sliceTotals","allTotals","total","totals","sort","sumOfRemaining","grandTotal","textContent","legendTotals","barWidth","divisor","_this3","NO_OF_YEAR_MONTHS","DAY_NAMES_SHORT","layerClass","layerTransform","makeElements","animateElements","store","layer","oldData","sliceStrings","strokeWidth","transition","newData","xPositions","widths","barHeight","barDepth","positions","position","newPos","newLabels","oldPos","oldLabels","calcLabels","_this5","newOptions","startPos","endPos","_this6","newStarts","oldStarts","colWidth","rowHeight","squareSize","xTranslate","serializedSubDomains","cols","week","weekNo","toUpperCase","yyyyMmDd","dataValue","square","unitType","units","yPositions","offsets","barsWidth","newXPos","newYPos","newOffsets","oldXPos","oldYPos","oldOffsets","hideLine","hideDots","valuesOverPoints","newValues","PercentageChart","barOptions","component","xPos","bars","get","gOff","pOff","formattedLabels","fraction","setValues","showTip","PieChart","mouseMove","mouseLeave","hoverRadio","startAngle","prevSlicesProperties","slicesProperties","curAngle","originDiffAngle","diffAngle","endAngle","prevProperty","curStart","curEnd","curPath","property","flag","calTranslateByAngle","g_off","pageX","pageY","formatted_labels","percent","slices","prevIndex","curActiveSliceIndex","prevAcitve","curActiveSlice","hoverSlice","COL_WIDTH","ROW_HEIGHT","Heatmap","countLabel","validStarts","startSubDomain","startSubDomainIndex","discreteDomains","spacing","noOfWeeks","setFullYear","dataPoints","timestampSec","firstWeekStart","domainConfigs","getDomains","lessCol","dayName","dayText","daySquares","comp","daySquare","dateParts","lessText","moreText","startMonth","startYear","noOfMonths","startOfMonth","getDomainConfig","startOfWeek","domainConfig","noOfMonthWeeks","getCol","empty","currentDate","currentDateWithinData","getSubDomainConfig","lineOptions","axisOptions","xAxisMode","yAxisMode","xIsSeries","shortenYAxisNumbers","formatTooltipX","calcXPositions","calcYAxisParameters","getAllYValues","makeDataByIndex","unitWidth","xOffset","xAxis","dataValues","intervalHeight","calcDatasetPoints","calcYExtremes","calcYRegions","scaleAll","cumulativeYs","replace","char","stacked","yExtremes","cumulativeYPos","cumulative","allValueLists","barDatasets","lineDatasets","barsConfigs","spaceRatio","lineConfigs","minLine","dotSize","markerConfigs","optionals","dataUnitComponents","dataByIndex","formatX","formatY","relX","relY","mapTooltipXPosition","dbi","yExtreme","formattedLabel","overlayGuides","currentIndex","currentUnit","_this7","setCurrentDataPoint","_this9","_this10","getDataPoint","datasetValues","splice","DonutChart","Chart"],"mappings":"AAAA,QAASA,aAAYC,EAAKC,OACX,KAARA,IAAiBA,KACtB,IAAIC,GAAWD,EAAIC,QAEnB,IAAKF,GAA2B,mBAAbG,UAAnB,CAEA,GAAIC,GAAOD,SAASC,MAAQD,SAASE,qBAAqB,QAAQ,GAC9DC,EAAQH,SAASI,cAAc,QACnCD,GAAME,KAAO,WAEI,QAAbN,GACEE,EAAKK,WACPL,EAAKM,aAAaJ,EAAOF,EAAKK,YAKhCL,EAAKO,YAAYL,GAGfA,EAAMM,WACRN,EAAMM,WAAWC,QAAUb,EAE3BM,EAAMK,YAAYR,SAASW,eAAed,KCvB9C,QAAgBe,GAAEC,EAAMC,SACA,gBAATD,IAAoBC,GAAOd,UAAUe,cAAcF,GAAQA,GAAQ,KA4ClF,QAAgBG,WAAUC,MACrBC,GAAOD,EAAQE,mCAKbD,EAAKE,KAAOpB,SAASqB,gBAAgBC,WAAatB,SAASuB,KAAKD,gBAC/DJ,EAAKM,MAAQxB,SAASqB,gBAAgBI,YAAczB,SAASuB,KAAKE,aAO1E,QAAgBC,UAASC,SACI,QAApBA,EAAGC,aAGZ,QAAgBC,qBAAoBF,MAE/BT,GAAOS,EAAGR,8BAGbD,GAAKE,KAAO,GACNF,EAAKM,MAAQ,GACbN,EAAKY,SAAWC,OAAOC,aAAehC,SAASqB,gBAAgBY,iBAC1DC,QAAUH,OAAOI,YAAcnC,SAASqB,gBAAgBe,aAIrE,QAAgBC,wBAAuBpB,MAClCqB,GAASP,OAAOQ,iBAAiBtB,GACjCuB,EAAUC,WAAWH,EAAOI,aAC/BD,WAAWH,EAAOK,oBAEZ1B,GAAQmB,YAAcI,EA2B9B,QAAgBI,MAAKC,EAAQxC,EAAMyC,MAC9BC,GAAM/C,SAASgD,YAAY,gBAE3BC,UAAU5C,GAAM,GAAM,OAErB,GAAI6C,KAAKJ,KACTI,GAAKJ,EAAWI,SAGdL,GAAOM,cAAcJ,GC7E7B,QAAgBK,cAAaC,SACrBA,GAAEC,YAAcD,EAAEE,QAAQnC,IAAMiC,EAAEG,SAASpC,IAGnD,QAAgBqC,eAAcJ,SACtBA,GAAEE,QAAQ/B,KAAO6B,EAAEG,SAAShC,KAGpC,QAAgBkC,gBAAeL,SACPA,GAAEE,QAAQnC,IAAMiC,EAAEE,QAAQzB,OAC9CuB,EAAEG,SAASpC,IAAMiC,EAAEG,SAAS1B,OAC5BuB,EAAEC,YAAcD,EAAEM,aAItB,QAAgBC,eAAcP,SACPA,GAAEE,QAAQ/B,KAAO6B,EAAEE,QAAQrB,MAC9CmB,EAAEG,SAAShC,KAAO6B,EAAEG,SAAStB,oHClDjC,QAAgB2B,UAASC,SACjBrB,YAAWqB,EAAEC,QAAQ,IAyC7B,QAAgBC,WAAUC,EAAOC,EAAOjD,MAASkD,0DAC5ClD,OACOkD,EAAQF,EAAM,GAAKA,EAAMA,EAAMG,OAAS,OAE/CC,GAAc,GAAIC,OAAMC,KAAKC,IAAIN,IAAQO,KAAKxD,YAC1CkD,EAAQE,EAAYK,OAAOT,GAASA,EAAMS,OAAOL,GAS1D,QAAgBM,gBAAeC,EAAQC,UAC9BD,EAAO,IAAIR,OAASS,EAyB7B,QAAgBC,oBAAmBC,EAAOC,YAErCT,KAAKU,IAAIF,EAAQG,aAAeF,IAChCT,KAAKY,IAAIJ,EAAQG,aAAeF,GASrC,QAAgBI,eAAcC,MAAWC,kEACpCC,OAAOC,MAAMH,SACMI,KAAdJ,MACCE,OAAOG,SAASL,MACjBC,GAAeD,EAAY,KAQrC,QAAgBM,OAAM7B,SAGdyB,QAAOhB,KAAKoB,MAAM7B,EAAI,MAAQ,OAOrC,QAAgB8B,WAAUP,MACtBQ,UAAQC,SAAOC,YAEfV,YAAqBW,YAChB,IAAIA,MAAKX,EAAUY,cAGH,qBAAdZ,wBAAAA,KAAwC,OAAdA,QAC5BA,KAGAf,MAAM4B,QAAQb,aAElBU,IAAOV,KACFA,EAAUU,KAEXA,GAAOH,UAAUE,SAGnBD,WC3IQM,sBAAqBC,EAAMC,MACtCC,UAAQC,eACRH,IAAQC,KACFA,EAAWD,IAChBA,MAEKA,EAAOC,IACZA,IAGGC,EAAQC,GAGjB,QAAgBC,sBAAqBC,EAAQC,MAC5CC,0DAAaD,EAAOtC,OAASqC,EAAOrC,aAGjCuC,GAAa,IACN3C,UAAUyC,EAAQE,KAElB3C,UAAU0C,EAAQC,IAEpBF,EAAQC,GAGjB,QAAgBE,gBAAeC,EAAKC,MAC9BD,QAGDA,GAAIzC,OAAS0C,EACTD,EAAIE,MAAM,EAAGD,EAAI,GAAK,MAEtBD,EAIT,QAAgBG,oBAAmBC,MAC9BC,aACiB,gBAAVD,GAAoBC,EAASD,MACnC,IAAqB,gBAAVA,OACN1B,OAAO0B,GACZ1B,OAAOC,MAAM0B,IAAS,MAAOD,MAI9BE,GAAI5C,KAAK6C,MAAM7C,KAAK8C,MAAM9C,KAAKC,IAAI0C,QACnCC,GAAK,EAAG,MAAOD,MACfI,GAAI/C,KAAK6C,MAAMD,EAAI,GACnBI,EAAahD,KAAKiD,IAAI,GAAIL,EAAQ,EAAJG,KAAWJ,EAAS3C,KAAKiD,IAAI,GAAIL,IAAIpD,QAAQ,SAGxEQ,MAAKoB,MAAgB,IAAV4B,GAAe,IAAM,KAAO,GAAI,IAAK,IAAK,IAAK,KAAKD,GAIvE,QAAgBG,yBAAwBC,EAAOC,OAG1C,GADAC,MACIC,EAAE,EAAEA,EAAEH,EAAMtD,OAAOyD,MACnBC,MAAMJ,EAAMG,GAAIF,EAAME,QAI1BE,GAAO,SAACC,EAAQC,MACfC,GAAUD,EAAO,GAAKD,EAAO,GAC7BG,EAAUF,EAAO,GAAKD,EAAO,iBAExBzD,KAAK6D,KAAK7D,KAAKiD,IAAIU,EAAS,GAAK3D,KAAKiD,IAAIW,EAAS,UACpD5D,KAAK8D,MAAMF,EAASD,KAIzBI,EAAe,SAACC,EAASC,EAAUC,EAAMC,MAGxCC,GAAIZ,EAFAS,GAAYD,EACZE,GAAQF,GAEZxD,EAAQ4D,EAAE5D,OAAS2D,EAAUnE,KAAKqE,GAAK,GACvCxE,EAfW,GAeFuE,EAAEvE,cACPmE,EAAQ,GAAKhE,KAAKY,IAAIJ,GAASX,EAC/BmE,EAAQ,GAAKhE,KAAKU,IAAIF,GAASX,UAUzB,UAACwD,EAAQiB,SAChBjB,GAAOkB,OAAO,SAACC,EAAKC,EAAOnB,EAAGoB,SAAY,KAANpB,EACrCmB,EAAM,OAAMA,EAAM,GAClBD,MAAOF,EAAQG,EAAOnB,EAAGoB,IAAM,KAGtBrB,EAZI,SAACoB,EAAOnB,EAAGoB,MAC1BC,GAAMZ,EAAaW,EAAEpB,EAAI,GAAIoB,EAAEpB,EAAI,GAAImB,GACvCG,EAAMb,EAAaU,EAAOC,EAAEpB,EAAI,GAAIoB,EAAEpB,EAAI,IAAI,cACtCqB,EAAI,OAAMA,EAAI,OAAMC,EAAI,OAAMA,EAAI,OAAMH,EAAM,OAAMA,EAAM,KCvExE,QAASI,YAAWC,SACfA,GAAI,IAAY,IACXA,EAAI,EAAU,EAChBA,EAGR,QAAgBC,oBAAmBC,EAAOC,MACrCC,GAAMC,SAASH,GACfI,GAAW,CACD,MAAVF,EAAI,OACDA,EAAI1C,MAAM,MACL,MAER6C,GAAMC,SAASJ,EAAI,IACnBJ,EAAID,YAAYQ,GAAO,IAAMJ,GAC7BM,EAAIV,YAAaQ,GAAO,EAAK,KAAUJ,GACvCO,EAAIX,YAAkB,IAANQ,GAAkBJ,UAC9BG,EAAS,IAAI,KAAOI,EAAKD,GAAK,EAAMT,GAAK,IAAKW,SAAS,IAGhE,QAAgBC,cAAarF,MAGxBsF,GAAS,mHADA,uCAECC,KAAKvF,IAAWsF,EAAOC,KAAKvF,GC7B3C,QAAShE,KAAEC,EAAMC,SACO,gBAATD,IAAoBC,GAAOd,UAAUe,cAAcF,GAAQA,GAAQ,KAGlF,QAAgBuJ,WAAUC,EAAK1B,MAC1B1H,GAAUjB,SAASsK,gBAAgB,6BAA8BD,OAEhE,GAAIxC,KAAKc,GAAG,IACZ4B,GAAM5B,EAAEd,MAEF,WAANA,MACD0C,GAAK/J,YAAYS,OAEf,IAAU,WAAN4G,EAAgB,IACpB/H,GAAMc,IAAE2J,KACRC,WAAWjK,aAAaU,EAASnB,KAC7BU,YAAYV,OAEJ,WAAN+H,EACQ,qBAAR0C,wBAAAA,YACFE,KAAKF,GAAKG,IAAI,cACZvK,MAAMwK,GAAQJ,EAAII,MAInB,cAAN9C,MAAyB,SACnB,cAANA,IACF,YAAyB0C,IAEjBK,aAAa/C,EAAG0C,UAKpBtJ,GAGR,QAAS4J,wBAAuBC,EAAYC,SACpCX,WAAU,yBACRU,KACJC,KACA,KACA,KACA,KACA,IAIN,QAASC,iBAAgBC,EAAUC,EAAQ3B,EAAO4B,SAC1Cf,WAAU,eACNa,uBACc1B,SACd2B,iBACMC,IAIlB,QAAgBC,kBAAiBC,EAAQC,EAAWC,EAAOjF,SACnD8D,WAAU,iBACLkB,SACHD,QACDE,SACCjF,IAIV,QAAgBkF,aAAYC,SACpBrB,WAAU,eACRqB,IAIV,QAAgBC,cAAaJ,MAAWK,0DAAU,GAAIN,6DAAO5F,GACxDmG,aACQN,YACAK,SAETN,KAAQO,EAAKC,OAASR,GAClBjB,UAAU,IAAKwB,GAWvB,QAAgBE,UAASC,SACjB3B,WAAU,yEAD0B,KAGvC2B,wEAHkD,mEAAa,6EAAoB,KAYxF,QAAgBC,gBAAeC,EAAeC,EAAaC,EAAQnH,MAAQoH,0DAAU,EAAGC,yDAAS,EAC3FC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAO5F,EAAI0F,EAAc1F,EAC9EkG,EAAqBN,EAAOI,EAAIL,EAAYK,EAAnCG,EAAsCP,EAAO5F,EAAI2F,EAAY3F,YAChE4F,EAAOI,MAAKJ,EAAO5F,YAC1B+F,MAAaE,aACZxH,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWC,OAGf,QAAgBC,eAAcV,EAAeC,EAAaC,EAAQnH,MAAQoH,0DAAU,EAAGC,yDAAS,EAC1FC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAO5F,EAAI0F,EAAc1F,EAC9EkG,EAA6BN,EAAOI,EAAIL,EAAYK,EAA3CK,EAAyD,EAAXT,EAAO5F,EAA7CmG,EAAoDP,EAAO5F,EAAI2F,EAAY3F,YACtF4F,EAAOI,MAAKJ,EAAO5F,YAC1B+F,MAAaE,aACZxH,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWG,cACVN,MAAaM,aACZ5H,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWC,OAGf,QAAgBG,sBAAqBZ,EAAeC,EAAaC,EAAQnH,MAAQoH,0DAAU,EAAGC,yDAAS,EACjGC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAO5F,EAAI0F,EAAc1F,EAC9EkG,EAAqBN,EAAOI,EAAIL,EAAYK,EAAnCG,EAAsCP,EAAO5F,EAAI2F,EAAY3F,YAEhE+F,MAAaE,aACnBxH,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWC,EAGf,QAAgBI,qBAAoBb,EAAeC,EAAaC,EAAQnH,MAAQoH,0DAAU,EAAGC,yDAAS,EAChGC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAO5F,EAAI0F,EAAc1F,EAC9EkG,EAA6BN,EAAOI,EAAIL,EAAYK,EAA3CK,EAAuD,EAAT5H,EAAawH,EAAnDE,EAA8DP,EAAO5F,EAAI0F,EAAc1F,YAElG+F,MAAaE,aACnBxH,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWG,YACVN,MAAaM,aACZ5H,MAAUA,QAAYqH,OAAYD,EAAY,EAAI,YACpDK,MAAWC,EAGf,QAAgBK,cAAajC,EAAYvB,MAAOyD,2DAC3CjC,EAAY,sBAA6BxB,EAAQ,KAAMyD,EAAU,UAAY,WAC7EC,EAAcpC,uBAAuBC,EAAYC,GACjDmC,GAAa,EAAG,GAAK,UACtBF,QACW,GAAK,GAAK,oBAGRC,EAAa,KAAM1D,EAAO2D,EAAU,oBACpCD,EAAa,MAAO1D,EAAO2D,EAAU,oBACrCD,EAAa,OAAQ1D,EAAO2D,EAAU,IAE/CnC,EAGR,QAAgBoC,eAAcZ,EAAGhG,EAAGgF,EAAOjF,MAC1C8G,0DAAMC,6BAA8B5I,yDAAK,aAkBlC2F,WAAU,kBAfL,mBACRmC,IACAhG,QACIgF,SACCjF,OACF7B,iBAEK6E,mBAAmB7E,GAAO,8BAGV6B,EAASiF,QAAUA,OAAUjF,iBACvC8G,KAOnB,QAAgBE,YAAWhC,EAAWiB,EAAGhG,EAAGgH,EAAMvI,MAAQP,0DAAK,OAAQ+I,4DAClE5B,aACQN,IACRiB,IACAhG,QACIgH,SACCA,KACJvI,OACEP,iBAGAgG,KAAK+C,GAAM9C,IAAI,cAChB3E,GAAOyH,EAAKzH,KAGXqE,UAAU,OAAQwB,GAG1B,QAAgB6B,WAAUlB,EAAGhG,EAAGgH,MAAM9I,0DAAK,OAAQwC,yEAC/BL,eAAeK,EAAOyG,iBAAmBzG,KAExD2E,cACQ,eACR,IACA,QACI2B,SACC,WACF9I,GAEHkJ,EAAOvD,UAAU,kBACT,wBACR,IACA,KACc,EAAZwD,UAAiB,iBACI,IAAZA,UAAmB,mBAClB,aACTC,oBACK5G,IAGR6G,EAAQ1D,UAAU,4BACGmC,OAAMhG,iBAEzB/F,YAAY4J,UAAU,OAAQwB,MAC9BpL,YAAYmN,GAEXG,EAGR,QAAgBC,WAAUxB,EAAGhG,EAAGgH,MAAM9I,0DAAK,OAAQwC,yEAC/BL,eAAeK,EAAOyG,iBAAmBzG,KAExD2E,cACQ,gBACP,KACA,IACD2B,OACG9I,GAEHkJ,EAAOvD,UAAU,kBACT,wBACR,IACA,KACEwD,UAAa,QACbA,UAAU,EAAK,iBACM,IAAZA,UAAmB,mBAClB,aACTC,oBACK5G,IAGR6G,EAAQ1D,UAAU,4BACGmC,OAAMhG,iBAEzB/F,YAAY4J,UAAU,SAAUwB,MAChCpL,YAAYmN,GAEXG,EAGR,QAAgBE,UAAS1C,EAAWiB,EAAGhG,EAAG0H,MAASC,6DAC9CC,EAAWD,EAAQC,UAAYP,gBAI5BxD,WAAU,kBACLkB,IACRiB,IACAhG,UANoBd,KAAfyI,EAAQE,GAAmBF,EAAQE,GAAMD,EAAW,GAOnD,iBACIA,EAAW,UAPdD,EAAQzJ,MAAQoJ,wBACVK,EAAQG,YAAc,kBAS3BJ,IAIb,QAASK,cAAa/B,EAAGtF,EAAOsH,EAAIC,MAAIN,4DACnCA,GAAQO,SAAQP,EAAQO,OAASC,oBACjCpH,GAAI8C,UAAU,kBACN,iBAAmB8D,EAAQ5C,aAClC,KACA,KACAiD,KACAC,iBAEKN,EAAQO,UAIdd,EAAOvD,UAAU,UACjB,IACAmE,EAAKC,EAAKD,EAAKI,aAAeJ,EAAKI,aAAef,aACjDA,UAAY,iBACHA,UAAY,mBACV,mBACJ3G,EAAQ,KAGhBc,EAAOqC,UAAU,4BACKmC,oBAGrB/L,YAAY8G,KACZ9G,YAAYmN,GAEV5F,EAGR,QAAS6G,cAAarI,EAAGU,EAAO4H,EAAIC,MAAIZ,4DACnCA,GAAQO,SAAQP,EAAQO,OAASC,iBACjCR,EAAQa,WAAUb,EAAQa,SAAW,IACrCb,EAAQc,iBAAgB/H,EAAQD,mBAAmBC,OAKnDK,GAAI8C,UAAU,kBAHF,mBAAqB8D,EAAQ5C,WACtB,WAArB4C,EAAQa,SAAwB,SAAU,OAIvCF,KACAC,KACA,KACA,iBAEKZ,EAAQO,UAIdd,EAAOvD,UAAU,UACjByE,EAAKC,EAAKD,EAAKF,aAAeE,EAAKF,eACnC,KACEf,UAAY,EAAI,EAAK,iBACbA,UAAY,mBACViB,EAAKC,EAAK,MAAQ,kBACtB7H,EAAM,KAGdc,EAAOqC,UAAU,+BACO7D,uBACT,UAGP,KAAToH,GAAuB,MAATA,MACXxN,MAAMsO,OAAS,2BAGhBjO,YAAY8G,KACZ9G,YAAYmN,GAEV5F,EAGR,QAAgBkH,OAAM1I,EAAGU,EAAOsE,MAAO2C,4DACjC9I,eAAcmB,KAAIA,EAAI,GAEvB2H,EAAQgB,MAAKhB,EAAQgB,IAAM,QAC3BhB,EAAQhD,SAAQgD,EAAQhD,OAAS,GACjCgD,EAAQiB,OAAMjB,EAAQiB,KAAO,QAC7BjB,EAAQO,SAAQP,EAAQO,OAASC,iBACjCR,EAAQ5C,YAAW4C,EAAQ5C,UAAY,OAEvCuD,IAAM,EAAIO,iBACVN,EAAsB,SAAjBZ,EAAQiB,KAAkB5D,EAAQ6D,iBAAmB,QAE1C,SAAjBlB,EAAQiB,MAAmC,UAAhBjB,EAAQgB,QAChC3D,EAAQ6D,mBACR7D,MAKA2C,EAAQhD,UACRgD,EAAQhD,OAEP0D,aAAarI,EAAGU,EAAO4H,EAAIC,UACzBZ,EAAQO,iBACLP,EAAQ5C,mBACT4C,EAAQa,wBACFb,EAAQc,iBAI1B,QAAgBK,OAAM9C,EAAGtF,EAAOX,MAAQ4H,4DAClC9I,eAAcmH,KAAIA,EAAI,GAEvB2B,EAAQgB,MAAKhB,EAAQgB,IAAM,UAC3BhB,EAAQhD,SAAQgD,EAAQhD,OAAS,GACjCgD,EAAQiB,OAAMjB,EAAQiB,KAAO,QAC7BjB,EAAQO,SAAQP,EAAQO,OAASC,iBACjCR,EAAQ5C,YAAW4C,EAAQ5C,UAAY,OAavCiD,GAAKjI,EAAS8I,iBACdZ,EAAsB,SAAjBN,EAAQiB,MAAmB,EAAIC,iBAAmB9I,QAEvC,SAAjB4H,EAAQiB,MAAmC,QAAhBjB,EAAQgB,SAE/B,EAAIE,mBACL,GAGCd,aAAa/B,EAAGtF,EAAOsH,EAAIC,UACzBN,EAAQO,iBACLP,EAAQ5C,mBACT4C,EAAQa,WAIpB,QAAgBO,SAAQ/I,EAAGU,EAAOsE,MAAO2C,4DACpCA,GAAQqB,WAAUrB,EAAQqB,SAAW,YAIrCC,GAAWpF,UAAU,kBACb,gBAJiB,SAArB8D,EAAQqB,SAAsBZ,aACnCpD,EAAQ5G,eAAesC,EAAO,GAAK0H,eAKlC,KACEf,WAAa,EAAK,iBACVA,UAAY,mBACV,kBACJ3G,EAAM,KAGdc,EAAO6G,aAAarI,EAAG,GAAI,EAAGgF,UACzB2C,EAAQO,QAAUC,0BACfR,EAAQ5C,WAAa,YACtB4C,EAAQa,oBAGdvO,YAAYgP,GAEVzH,EAGR,QAAgB0H,SAAQlB,EAAIC,EAAIjD,EAAOtE,MAAOiH,6DAEzC5H,EAASiI,EAAKC,EAEdtN,EAAOkJ,UAAU,6EAIXsE,mCACenD,OAAUjF,KAG/B,IACA,QACIiF,SACCjF,GAGL4H,GAAQqB,WAAUrB,EAAQqB,SAAW,YAIrCC,GAAWpF,UAAU,kBACb,gBAJiB,SAArB8D,EAAQqB,SAAsBZ,aACnCpD,EAAQ5G,eAAesC,EAAM,GAAI,KAAO0H,eAKvC,KACEf,WAAa,EAAK,iBACVA,UAAY,mBACV,kBACJ3G,EAAM,KAGdyI,EAAStF,UAAU,+BACKoE,iBAGrBhO,YAAYU,KACZV,YAAYgP,GAEZE,EAGR,QAAgBC,YAAWpD,EAAGnG,EAAMmF,EAAOhC,MAAOtC,0DAAM,GAAI2I,yDAAM,EAAG1E,yDAAO,EAAG2E,8DAC5D1J,qBAAqBC,EAAMyJ,EAAKxJ,gCAA7CC,OAAQC,UACR2E,EAES,IAAX5E,MACOuJ,EAAKC,aACTD,EAAKC,WAIN1K,cAAcmH,KAAIA,EAAI,GACtBnH,cAAcmB,KAAIA,EAAI,GACtBnB,cAAckB,GAAQ,KAAOA,EAAS,GACtClB,cAAcmG,GAAO,KAAOA,EAAQ,MAErCrK,GAAOkJ,UAAU,4CAEJb,qBACIqG,IACjBrD,IACAhG,QACIgF,SACCjF,WAGA,KAEKW,EAAM7C,OAEb,GACDwG,aAAa,IAAK,KAClBA,aAAa,IAAK,MACnB+C,GAAOvD,UAAU,kBACT,qBACRmB,EAAM,IACN,KACEqC,UAAY,GAAK,EAAK,iBACdA,UAAY,mBACV,mBACJ3G,IAGR6G,EAAQ1D,UAAU,wBACDwF,yBACIrD,OAAMhG,iBAEzB/F,YAAYU,KACZV,YAAYmN,GAEXG,QArBA5M,GAyBT,QAAgB6O,YAAWxD,EAAGhG,EAAGvB,EAAQuE,MAAOtC,0DAAM,GAAI2I,yDAAM,EAC3DI,EAAM5F,UAAU,yBACHb,qBACIqG,KAChBrD,KACAhG,IACDvB,WAGK,KAEKiC,EAAM7C,OAEb,GACFwG,aAAa,KAAM,KACnBA,aAAa,KAAM,MAEnB+C,GAAOvD,UAAU,kBACT,qBACR,IACA,KACEwD,UAAY,GAAK,EAAI5I,EAAU,iBACvB4I,UAAY,mBACV,mBACJ3G,IAGR6G,EAAQ1D,UAAU,wBACDwF,yBACIrD,OAAMhG,iBAEzB/F,YAAYwP,KACZxP,YAAYmN,GAEXG,QAtBAkC,GA0BT,QAAgBC,UAASvI,EAAOC,EAAO4B,MAAO2E,6DAAY2B,4DAErDK,EADavI,EAAM+C,IAAI,SAACnE,EAAGsB,SAAOH,GAAMG,GAAK,IAAMtB,IAC5B4J,KAAK,IAG5BjC,GAAQkC,SACXF,EAAYzI,wBAAwBC,EAAOC,OAExC0I,GAAOvE,SAAS,IAAIoE,EAAW,kBAAmB3G,MAGnD2E,EAAQoC,SAAU,IAChBC,GAAcxD,aAAa8C,EAAKW,QAASjH,KACxCpJ,MAAMsO,eAAiB8B,SAGzBE,SACGJ,MAIJnC,EAAQwC,WAAY,IAClBC,GAAqB5D,aAAa8C,EAAKW,QAASjH,GAAO,GAEvDwC,EAAU,IAASrE,EAAM,OAAMmI,EAAKxJ,aAAc6J,MAAgBxI,EAAMX,OAAO,GAAG,OAAM8I,EAAKxJ,WAC3FqJ,OAAS5D,SAASC,gBAAwB,eAAgB4E,aAG1DF,GChmBR,QAAgBG,WAAUC,EAAMC,EAAUC,EAAUC,MAC/CC,GAA0B,gBAAbH,GAAwBA,EAAWA,EAASX,KAAK,aAEjEU,GACClF,UAAWoF,EAASZ,KAAK,OAC1Ba,EACAE,WACA,aACCvF,UAAWsF,IAId,QAAgBE,mBAAkB9B,EAAO+B,EAAMC,SACvCT,WAAUvB,GAAQgC,EAAM,IAAKD,EAAM,GAAIE,sBAG/C,QAAgBC,mBAAkBtC,EAAOuC,EAAMC,SACvCb,WAAU3B,GAAQ,EAAGwC,IAAQ,EAAGD,GAAOF,sBAG/C,QAAgBI,eAAcC,EAAWC,EAAOC,EAAOC,MAClDC,GAAYH,EAAQC,EACpB3Q,EAAOyQ,EAAUK,WAAW,WAG/B9Q,GACEoF,OAAQyL,EAAWE,mBAHV/Q,EAAKgR,aAAa,cAGyBH,GACtDT,qBACAJ,YAGeN,UAAUe,GAAY,EAAGG,IAAS,EAAGD,GAAQP,uBAI9D,QAAgBa,YAAWC,EAAK7F,EAAGnG,EAAMmF,MAAOL,0DAAO,IACpC/E,qBAAqBC,8DAAWC,kCAA7CC,OAAQC,iBACR2E,EACe,SAAjBkH,EAAIC,WACKD,EAAIJ,WAAW,IAGxBzG,MAAOA,EAAOjF,OAAQA,GACvBgM,cACApB,YAIeN,UAAUwB,EADRA,EAAIF,aAAa,aAAaK,MAAM,KAAK,GAAGxL,MAAM,GAAI,IAC3BwF,EAAGhG,GAAI+K,yBAG3Cc,GAAM7G,MAAOA,EAAOjF,OAAQA,EAAQiG,EAAGA,EAAGhG,EAAGA,GAAI+L,cAAepB,aAK3E,QAAgBsB,YAAWxC,EAAKzD,EAAGhG,SACd,WAAjByJ,EAAIqC,UAEUzB,UAAUZ,EADRA,EAAIkC,aAAa,aAAaK,MAAM,KAAK,GAAGxL,MAAM,GAAI,IAC3BwF,EAAGhG,GAAI+K,yBAG3CtB,GAAMyC,GAAIlG,EAAGmG,GAAInM,GAAI+L,cAAepB,aAK/C,QAAgByB,aAAYlC,EAAOmC,EAAUC,EAAUxM,EAAU+J,MAC5D0C,MACA5C,EAAY2C,EAASnI,IAAI,SAACnE,EAAGsB,SAAO+K,GAAS/K,GAAK,IAAMtB,IAAI4J,KAAK,IAEjEC,KACHF,EAAYzI,wBAAwBmL,EAAUC,OAEzCE,IAAYtC,EAAMJ,MAAOvM,EAAE,IAAMoM,GAAY8C,cAAe9B,iBACnDpJ,KAAKiL,GAEjBtC,EAAMf,OAAQ,IACZuD,GAAgBL,EAAS,OAAMvM,MAC/B6M,MAAeN,EAAS7L,OAAO,GAAG,QAAOV,EAEvC8M,GACL1C,EAAMf,QACL5L,EAAE,IAAMmP,EAAa/C,EAAYgD,GAClCF,cACA9B,cAEcpJ,KAAKqL,SAGdL,GAGR,QAAgBM,gBAAeC,EAAStH,UAC/BsH,GAAUvP,EAAGiI,GAAUuG,cAAepB,uJC1F/C,QAASoC,mBAAkBrS,EAASsS,EAAOC,MAAKC,0DAAW,SAAUpT,6DAAKoF,GAAWiO,4DAEhFC,EAAc1S,EAAQ2S,WAAU,GAChCC,EAAa5S,EAAQ2S,WAAU,OAE/B,GAAIE,KAAiBP,GAAO,IAC3BQ,YACiB,cAAlBD,EACe9T,SAASsK,gBAAgB,6BAA8B,oBAEvDtK,SAASsK,gBAAgB,6BAA8B,cAErE0J,GAAeN,EAAUI,IAAkB7S,EAAQiR,aAAa4B,GAChEhO,EAAQyN,EAAMO,GAEdG,iBACYH,OACTE,KACFlO,QACG,SACF0N,EAAI,IAAO,WACRQ,EAAe,IAAMlO,aACjBoO,OAAOT,YACT,eACA,cACJ,SAGJpT,OACF,KAAmBA,OAGf,GAAIwH,KAAKoM,KACErJ,aAAa/C,EAAGoM,EAASpM,MAG7BrH,YAAYuT,GAErB1T,IACSuK,aAAakJ,eAA4BhO,SAEzC8E,aAAakJ,EAAehO,UAIjC6N,EAAaE,GAGtB,QAAgBlI,WAAU1K,EAASd,KAC1BA,MAAMwL,UAAYxL,IAClBA,MAAMgU,gBAAkBhU,IACxBA,MAAMiU,YAAcjU,IACpBA,MAAMkU,aAAelU,IACrBA,MAAMmU,WAAanU,EAG5B,QAASoU,YAAW9I,EAAc+I,MAC7BC,MACAC,OAEKhK,IAAI,eACRmG,GAAO5P,EAAQ,GACfoK,EAASwF,EAAKrG,WAEdmJ,SAAaE,WAET,GAAKhD,QACeyC,oDAAqBrS,4CAErC6G,KAAK+L,KACJ/L,MAAM6L,EAAatI,IAE5BA,KACIsJ,aAAahB,EAAa9C,QAI/B+D,GAAUnJ,EAAamI,WAAU,YAExBlJ,IAAI,SAACiJ,EAAa9L,GAC1B8L,EAAY,OACH,GAAGgB,aAAaF,EAAY5M,GAAI8L,EAAY,MAC/C9L,GAAG,GAAK4M,EAAY5M,MAIxB+M,EAGR,QAAgBC,kBAAiBxJ,EAAQyJ,EAAYC,MACpB,IAA7BA,EAAkB3Q,WAEjB4Q,GAAiBT,WAAWO,EAAYC,EACzCD,GAAWtK,YAAca,MACpB4J,YAAYH,KACZtU,YAAYwU,eAKT,WACPA,EAAexK,YAAca,MACxB4J,YAAYD,KACZxU,YAAYsU,KAElBI,sBCnHG,QAASC,cAAaC,EAAU5H,MAClCvE,GAAIjJ,SAASI,cAAc,OAC7BD,MAAQ,mBACNkV,GAAO,GAAIC,MAAK9H,GAAOnN,KAAM,iCAC7BkV,EAAMxT,OAAOyT,IAAIC,gBAAgBJ,KACnCK,KAAOH,IACPI,SAAWP,WACJ7T,KAAKf,YAAYyI,KACxB2M,mBACS,oBACDrU,KAAK0T,YAAYhM,UACnBuM,IAAIK,gBAAgBN,IACzB,KAGJ,QAAgBO,kBAAiBC,MAC5BC,GAAQD,EAAInC,WAAU,KACpBqC,UAAUC,IAAI,qBACdtL,aAAa,QAAS,gCACtBA,aAAa,cAAe,mCAC9BuL,GAAUvV,EAAEwV,OAAO,mBACTC,YAER9V,aAAa4V,EAASH,EAAM1V,eAE9BgW,GAAY1V,EAAEwV,OAAO,gBACf5V,YAAYwV,GAEfM,EAAUC,yuBCblB,QAASC,YAAWC,MACfC,GAAS,GAAI1Q,MAAKyQ,YACfE,WAAWD,EAAOE,aAAeF,EAAOG,qBACxCH,EAGR,QAAgBI,aAAYL,MACvBM,GAAKN,EAAKO,UACVC,EAAKR,EAAKS,WAAa,SAE1BT,EAAKU,eACJF,EAAG,EAAI,GAAK,KAAOA,GACnBF,EAAG,EAAI,GAAK,KAAOA,GACnB5G,KAAK,KAGR,QAAgB6F,OAAMS,SACd,IAAIzQ,MAAKyQ,EAAKxQ,WAiBtB,QAAgBmR,iBAAgBC,EAAWC,MACtCC,GAAgBC,eAAeH,SAC5B9S,MAAKkT,KAAKC,eAAeH,EAAeD,GAAWK,oBAG3D,QAAgBD,gBAAeL,EAAWC,MACrCM,GAAqBC,WAAaC,oBAC9BtB,WAAWc,GAAWd,WAAWa,IAAcO,EAGxD,QAAgBG,gBAAeV,EAAWC,SAClCD,GAAUH,aAAeI,EAAQJ,YACpCG,EAAUF,gBAAkBG,EAAQH,cAGzC,QAAgBa,cAAanQ,MAAGoQ,2DAC3BC,EAAYC,YAAYtQ,SACrBoQ,GAAQC,EAAUnR,MAAM,EAAG,GAAKmR,EAGxC,QAAgBE,oBAAoBC,EAAOC,SACnC,IAAItS,MAAKsS,EAAMD,EAAQ,EAAG,GAIlC,QAAgBb,gBAAef,MAC1B8B,GAAUvC,MAAMS,GACd+B,EAAMD,EAAQE,eACT,KAARD,WACMD,GAAW,EAAKC,GAElBD,EAIR,QAAgBG,SAAQjC,EAAMkC,KACxBC,QAAQnC,EAAKO,UAAY2B,iHC6V/B,QAAgBE,cAAaC,EAAMC,EAAWC,MACzCvO,GAAOwO,OAAOxO,KAAKyO,kBAAkBC,OAAO,kBAAKL,GAAKM,SAASC,KAC/DC,EAASJ,iBAAiBzO,EAAK,kBAC5B8O,OAAOD,aACFP,UACFC,IAEH,GAAIQ,gBAAeF,goDC5b3B,QAESG,WAAUlN,MAKX,IAAJA,SACM,EAAG,MAET/G,MAAM+G,UACAmN,UAAW,iBAAkBC,SAAU,QAE5CC,GAAMrN,EAAI,EAAI,GAAK,MACnB7G,SAAS6G,UACJmN,SAAgB,iBAANE,EAAwBD,SAAU,OAGjDpV,KAAKC,IAAI+H,MACTsN,GAAMtV,KAAK6C,MAAM7C,KAAK8C,MAAMkF,WAGxBqN,GAFErN,EAAEhI,KAAKiD,IAAI,GAAIqS,IAENA,GAGpB,QAASC,wBAAuBC,MAAKC,0DAAI,EACpCC,EAAa1V,KAAKkT,KAAKsC,GACvBG,EAAa3V,KAAK6C,MAAM4S,GACxBG,EAAQF,EAAaC,EAErBE,EAAYD,EACZE,EAAW,CAGZF,GAAQ,IACPA,EAAQ,GAAM,UAGKD,KAEVC,EAAM,IACP,GAITA,GAAS,MAEAA,KADC,IAKA,IAAVA,MACU,IACD,OAIR,GADAG,MACIzS,EAAI,EAAGA,GAAKuS,EAAWvS,MACpBC,KAAKoS,EAAaG,EAAWxS,SAEjCyS,GAGR,QAASC,mBAAkBC,MAAUC,0DAAS,IACZhB,UAAUe,2BAAtCE,OAAgBf,OACjBgB,EAAiBF,EAAWA,EAASlW,KAAKiD,IAAI,GAAImS,GAAW,EAK7DW,EAAYR,yBAFCY,EAAe3W,QAAQ,GAEe4W,YAC3CL,EAAU5P,IAAI,kBAAS5E,GAAQvB,KAAKiD,IAAI,GAAImS,KAIzD,QAAgBiB,oBAAmBC,WAYzBC,GAA0BN,EAAUO,OAOxC,GANAT,GAAYC,kBAAkBC,GAE9BQ,EAAeV,EAAU,GAAKA,EAAU,GAGxCxU,EAAQ,EACJ+B,EAAI,EAAG/B,EAAQiV,EAAalT,OAC1BmT,IACCC,SAAU,EAAKnV,SAEnBwU,MAvBkCY,2DAMtCV,EAAWjW,KAAKwV,oCAAOc,IACvBJ,EAAWlW,KAAKyV,oCAAOa,IAGTP,QAkBfE,GAAY,GAAKC,GAAY,EACpBhB,UAAUe,GAAU,KAC3BU,EAGSX,kBAAkBC,EAAUC,GAF5BF,kBAAkBC,OAQ3B,IAAGA,EAAW,GAAKC,EAAW,EAAG,IAOjCM,GAAcxW,KAAKC,IAAIiW,EAExBD,IAAYO,GACHtB,UAAUe,GAAU,KACnBM,EAA0BN,EAAUO,KAGrCtB,UAAUsB,GAAa,KACfD,EAA0BC,EAAaP,GACjC9R,UAAUgC,IAAI,mBAAW,EAAN5G,SAOzC,IAAG0W,GAAY,GAAKC,GAAY,EAAG,IAInCU,GAAiB5W,KAAKC,IAAIiW,GAC1BW,EAAiB7W,KAAKC,IAAIgW,EAEnBf,WAAU0B,GAAgB,QACjCD,EAGSX,kBAAkBY,EAAgBC,GAFlCb,kBAAkBY,IAKTzS,UAAUgC,IAAI,mBAAW,EAAN5G,UAGnCwW,GAGR,QAAgBe,cAAaC,MAExBC,GAAWC,gBAAgBF,SAC5BA,GAAKG,QAAQ,IAAM,EAGTH,EAAKG,QAAQ,GAChBH,EAAK,GAAK,GAIL,EADJA,EAAK,GACUC,GAKX,EADJD,EAAKA,EAAKlX,OAAS,GACJmX,GAAYD,EAAKlX,OAAS,GAiBrD,QAAgBoX,iBAAgBE,SACxBA,GAAa,GAAKA,EAAa,GAGvC,QAAgBC,eAAcD,SACtBA,GAAaA,EAAatX,OAAO,GAAKsX,EAAa,GAG3D,QAAgBE,OAAMrR,EAAKsR,SACnBhY,UAASgY,EAAMxV,SAAWkE,EAAMsR,EAAMC,iBAY9C,QAAgBC,mBAAkBC,EAAMC,MAAKrM,2DACxCsM,EAAUD,EAAInT,OAAO,SAASqT,EAAMC,SAC/B7X,MAAKC,IAAI4X,EAAOJ,GAAQzX,KAAKC,IAAI2X,EAAOH,GAAQI,EAAOD,aAGzDvM,GAAQqM,EAAIR,QAAQS,GAAWA,EAGvC,QAAgBG,kBAAiBxB,EAAQyB,OASpC,GALAC,GAAehY,KAAKwV,oCAAOc,IAE3B2B,EAAmB,GAAKF,EAAmB,GAC3CG,KAEI5U,EAAI,EAAGA,EAAIyU,EAAkBzU,IAAK,IACrC6U,GAAaH,GAAgBC,EAAmB3U,KACvCC,KAAK4U,SAGZD,GAGR,QAAgBE,kBAAiB7W,EAAO2W,SAChCA,GAAatD,OAAO,kBAAKrV,GAAIgC,IAAO1B,84BC7O5C,QAGgBwY,UAASpP,EAAMnN,KACzBwc,OAASrP,EAAKqP,cAEfC,GAAgBtP,EAAKqP,OAAOzY,OAG5B2Y,EAAWvP,EAAKuP,SAChBC,EAAY,GAAI1Y,OAAMwY,GAAerY,KAAK,SAC1CsY,gBAGMC,OAIDtS,IAAI,eAER5G,EAAE+W,OAEC,IAEFoC,GAAOnZ,EAAE+W,YACNoC,EAAKvS,IAAI,kBAASlF,OAAM+E,GAAa,EAANA,KAG9BnG,OAAS0Y,EACTG,EAAKlW,MAAM,EAAG+V,GAEd9Y,UAAUiZ,EAAMH,EAAgBG,EAAK7Y,OAAQ,KAEnDyW,OAASoC,SAZTpC,OAASmC,CAgBRlZ,GAAEoZ,YACDC,yBAAyB/D,SAAS/Y,KACpC6c,UAAY7c,KASbmN,EAAK4P,YACFA,SAAS1S,IAAI,eACd5G,EAAEuZ,IAAMvZ,EAAEK,MAAO,QACCL,EAAEuZ,IAAKvZ,EAAEK,SAA1BA,aAASkZ,YAKR7P,EAGR,QAAgB8P,cAAaC,MACxBT,GAAgBS,EAASV,OAAOzY,OAChC4Y,EAAY,GAAI1Y,OAAMwY,GAAerY,KAAK,GAE1C+Y,UACKD,EAASV,OAAO9V,MAAM,GAAI,YACxBwW,EAASR,SAASrS,IAAI,wBAExB,UACEsS,EAAUjW,MAAM,GAAI,aACjBjD,EAAEoZ,oBAKbK,GAASE,aACFA,iBAEA,QACA,MAKPF,EAASH,aACFA,iBAEA,MACF,QACE,MAKHI,EAGR,QAAgBE,oBAAmBC,MAAYd,6DAAWe,6DACrDC,EAAeF,EAAad,EAAOzY,MACpCyZ,IAAgB,IAAGA,EAAe,MACjCC,GAAiBD,EAAeE,mBAEhCC,YACDJ,EAAU,IAERK,GAAiB1Z,KAAKwV,oCAAO8C,EAAOnS,IAAI,kBAASzD,GAAM7C,aAC1CG,KAAKkT,KAAKwG,EAAeH,SAG1BjB,GAAOnS,IAAI,SAACzD,EAAOY,aAC1B,IACAzD,OAAS0Z,IAEbF,EAOA/V,EAAImW,GAAmB,MACjB,MAPNF,EAAe,EAAI,EACb7W,EAAMF,MAAM,EAAG+W,EAAe,GAAK,OAEnC7W,EAAMF,MAAM,EAAG+W,GAAkB,MAQrC7W,wmDCzGT,QAASiX,qBAAehB,0DAAY,OAAQ7R,eAAQ6C,qBACjC,eAAdgP,KACK7c,KAAO,OACR,GAAI8d,WAAU9S,EAAQ6C,IAGzBkQ,WAAWlB,GAKT,GAAIkB,YAAWlB,GAAW7R,EAAQ6C,gBAJhCmQ,MAAM,yBAA2BnB,+9DbZ3Ctc,GAAEwV,OAAS,SAAC/L,EAAK1B,MACZ1H,GAAUjB,SAASI,cAAciK,OAEhC,GAAIxC,KAAKc,GAAG,IACZ4B,GAAM5B,EAAEd,MAEF,WAANA,IACD0C,GAAK/J,YAAYS,OAEf,IAAU,WAAN4G,EAAgB,IACpB/H,GAAMc,EAAE2J,KACRC,WAAWjK,aAAaU,EAASnB,KAC7BU,YAAYV,OAEJ,WAAN+H,EACQ,qBAAR0C,sBAAAA,YACFE,KAAKF,GAAKG,IAAI,cACZvK,MAAMwK,GAAQJ,EAAII,KAGlB9C,IAAK5G,KACP4G,GAAK0C,IAGLK,aAAa/C,EAAG0C,SAInBtJ,GCxBD,IAAMqd,6BAEN,UACG,QACF,SACC,kBAGF,UACG,QACF,SACC,eAGI,gBACC,gBACC,iBAEC,IAyBHC,0BAA4B,IAC5BC,2BAA6B,IAE7BC,wBAA0B,OAC1BtB,0BAA4B,OAAQ,OAEpCuB,qBAAuB,IAEvBC,sBAAwB,GACxBC,uBAAyB,EAEzBC,oBAAsB,EACtBC,sBAAwB,EAExBC,8BAAgC,GAChC1R,6BAA+B,EAI/B2R,0BAA4B,EAE5BC,oBAAsB,GACtBC,oBAAsB,EAEtBnB,mBAAqB,EAErBoB,gCAAkC,EAEzCC,sBAAwB,aAAc,OAAQ,SAAU,MAAO,SACpE,SAAU,QAAS,cAAe,SAAU,UAAW,aAAc,aAChEC,sBAAwB,UAAW,UAAW,UAAW,UAAW,WAI7DC,oBACPF,0BACCA,yBACDA,gCACOA,6BACHC,2BACFD,sBAIKla,YAAcX,KAAKqE,GAAK,IACxB2W,WAAa,sQavGLC,wCAEnBnU,OAAAA,aAAS,WACToU,OAAAA,iDAEKpU,OAASA,OACToU,OAASA,OACTC,UAAY,QACZC,WAAa,QACbC,mBACAC,gBAAkB,OAElBtT,EAAI,OACJhG,EAAI,OAEJnF,IAAM,OACNI,KAAO,OAEPse,oEAIAC,qDAIAtb,YACAub,qEAIA1J,UAAY1V,EAAEwV,OAAO,cACjB6J,KAAK5U,iBACF,8JAKP6U,eAEAC,MAAQF,KAAK3J,UAAUvV,cAAc,eACrCqf,cAAgBH,KAAK3J,UAAUvV,cAAc,yBAE7CsK,OAAOgV,iBAAiB,aAAc,aACrCH,sDAKFC,QACDF,MAAKrQ,YACF0G,UAAU1L,aAAa,mBAAoBqV,KAAKrQ,SAEnDqQ,KAAKJ,2BACYI,KAAKN,uBAAsBM,KAAKP,UAExCO,KAAKP,qBAAoBO,KAAKN,4BAErCQ,MAAM5J,UAAY4J,OAClBC,cAAc7J,UAAY,QAE1BqJ,WAAWlV,IAAI,SAAC4V,EAAKzY,MACnB0B,GAAQgX,EAAKd,OAAO5X,IAAM,QAC5B/B,EAA0B,IAAlBwa,EAAIE,WAAmBF,EAAIE,UAAYF,EAAIE,UAAYF,EAAIxa,MAEnE2a,EAAK7f,EAAEwV,OAAO,wCAEW7M,iDAE6B,IAAVzD,GAAeA,EAAQA,EAAQ,6BAC3Ewa,EAAIH,MAAQG,EAAIH,MAAQ,QAGvBC,cAAc5f,YAAYigB,+CAK5BlV,GAAQ0U,KAAK3J,UAAUoK,iBAEtBtf,IAAM6e,KAAK1Z,EAAI0Z,KAAK3J,UAAUqK,aAChCxB,qCACE3d,KAAOye,KAAK1T,EAAIhB,EAAM,KACvBqV,GAAUX,KAAK5U,OAAOqV,YAAcnV,EAEpCsV,EAAUZ,KAAK3J,UAAUvV,cAAc,mBAExCkf,KAAKze,KAAO,IACNrB,MAAMqB,oBAAsB,EAAIye,KAAKze,gBACxCA,KAAO,MACN,IAAGye,KAAKze,KAAOof,EAAS,IAE1BE,kBADQb,KAAKze,KAAOof,WAEhBzgB,MAAMqB,KAAOsf,OAEhBtf,KAAOof,SAEJzgB,MAAMqB,6CAIN+K,EAAGhG,MAAG4Z,6DAAYP,4DAAiBhQ,0DAAS,OAChD8P,UAAYS,EAAMrH,UAClB6G,WAAaQ,EAAMra,WACnB8Z,WAAaA,OACbrT,EAAIA,OACJhG,EAAIA,OACJsZ,gBAAkBM,EAAMY,YAAc,OACtCnR,MAAQA,OACRoR,iDAIA1K,UAAUnW,MAAMiB,IAAM,WACtBkV,UAAUnW,MAAMqB,KAAO,WACvB8U,UAAUnW,MAAMgL,QAAU,2CAI1BmL,UAAUnW,MAAMiB,IAAM6e,KAAK7e,IAAM,UACjCkV,UAAUnW,MAAMqB,KAAOye,KAAKze,KAAO,UACnC8U,UAAUnW,MAAMgL,QAAU,iOV5H3B8V,+BACS,eACN,iBACE,cACH,iBACG,iBACA,gBACD,wBACM,iBACL,kBACC,gBACF,eACD,uBACM,sBACD,WA8BDvX,SAAW,SAACH,SAEpB,4BAA6BY,KAAKZ,iCACE2X,KAAK3X,GAC1CmB,IAAI,SAAC6B,EAAG1E,SAAa,KAANA,EAAUtC,OAAOgH,GAAGvC,SAAS,IAAM,MAClDlB,OAAO,SAACqY,EAAGC,YAAUD,EAAIC,IAErBH,iBAAiB1X,IAAUA,0oBC9CtB6F,iBAAmB,EAC1BT,aAAe,EACfjB,gBAAkB,GACXE,UAAY,GACnBc,gBAAkB,UAClBb,UAAY,UAkmBPwT,iBACH,SAACxQ,MACHyQ,SACiB,UAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBuP,GAAU1Q,EAAK+C,qBACXzT,MAAMsE,KAAO,YACbtE,MAAMgL,QAAU,MAErBmW,KACM1W,aAAa,YAAa0W,GAE5BC,OAGD,SAAC1Q,MACHyQ,SACiB,YAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBuP,GAAU1Q,EAAK+C,YACf5O,EAAS6L,EAAKqB,aAAa,KAC3BzN,EAAOoM,EAAKqB,aAAa,iBACrBtH,aAAa,IAAKf,SAAS7E,GAAU8Z,yBACrClU,aAAa,OAAQnG,KACrBtE,MAAMgL,QAAU,MAErBmW,KACM1W,aAAa,YAAa0W,GAE5BC,eAGO,SAAC1Q,MACXyQ,SACiB,YAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBuP,GAAU1Q,EAAK+C,YACf5O,EAAS6L,EAAKqB,aAAa,KAC3BzN,EAAOoM,EAAKqB,aAAa,iBACrBtH,aAAa,IAAKf,SAAS7E,GAAU8Z,yBACrClU,aAAa,OAAQnG,KACrBtE,MAAMgL,QAAU,MAErBmW,KACM1W,aAAa,YAAa0W,GAE5BC,IAIEC,mBACH,SAAC3Q,EAAM0Q,MACTD,SACiB,UAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpByP,IAAc,IAAK,IAAK,QAAS,iBAC9B5G,OAAOhK,EAAK4Q,YACjBtI,OAAO,kBAAQsI,GAAWrI,SAASsI,EAAK5I,OAAS4I,EAAKC,YACtDjX,IAAI,cACIE,aAAa8W,EAAK5I,KAAM4I,EAAKE,aAGpCN,KACM1W,aAAa,YAAa0W,QAI7B,SAACzQ,EAAM0Q,MACTD,SACiB,YAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpByP,IAAc,KAAM,aACjB5G,OAAOhK,EAAK4Q,YACjBtI,OAAO,kBAAQsI,GAAWrI,SAASsI,EAAK5I,OAAS4I,EAAKC,YACtDjX,IAAI,cACIE,aAAa8W,EAAK5I,KAAM4I,EAAKE,aAGpCN,KACM1W,aAAa,YAAa0W,gBAIrB,SAACzQ,EAAM0Q,MACjBD,SACiB,YAAlBzQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpByP,IAAc,KAAM,aACjB5G,OAAOhK,EAAK4Q,YACjBtI,OAAO,kBAAQsI,GAAWrI,SAASsI,EAAK5I,OAAS4I,EAAKC,YACtDjX,IAAI,cACIE,aAAa8W,EAAK5I,KAAM4I,EAAKE,aAGpCN,KACM1W,aAAa,YAAa0W,0bCrtBxBhP,cAAgB,IAChBU,cAAgB,IAChB1B,qBAAuBgB,cACvB4C,oBAAsB,IAEtBhE,WAAa,8bCHpBgD,aACC,yBACE,iBAEA,wBACC,uBACE,iBQVCmC,QAAU,48DCUFwL,gCACRxW,EAAQ6C,kCAETtI,UAAUsI,QAEf7C,OAA2B,gBAAXA,GAClBrL,SAASe,cAAcsK,GACvBA,IAEG4U,KAAK5U,iBAAkByW,mBACtB,IAAIC,OAAM,uDAGZC,aAAe9T,OAEfiS,MAAQjS,EAAQiS,OAAS,QACzB9f,KAAO6N,EAAQ7N,MAAQ,QAEvBkd,SAAW0C,KAAKgC,YAAY/T,EAAQV,WACpCA,KAAOyS,KAAKiC,iBAAiBjC,KAAK1C,eAElCkC,OAASQ,KAAKkC,eAAejU,EAAQuR,OAAQQ,KAAK5f,WAElDiZ,oBACS,aACD,cACCpL,EAAQkU,aAAe,cACC,KAApBlU,EAAQmU,QAA2BnU,EAAQmU,QAAU,kBACrDnU,EAAQoU,iBAAmB,QAGxCC,SAAWC,KAAKC,MAAMD,KAAKE,UAAUpE,mBACtCjb,GAAI4c,KAAKsC,cACRI,YAAYzU,GACb+R,KAAKE,MAAM/b,WAAYd,YAAc,GACrC2c,KAAK3G,OAAOsJ,aAAYvf,EAAEM,aAAe,QACxCkf,UAAY3U,EAAQ5H,QAAUjD,EAAEyf,gBAEhCC,cACA7U,gBAEA8U,YAAczE,0BAEhB0B,KAAK3G,OAAO8I,mBACTa,kBAGDC,UAAUhV,8DAGJV,SACJA,4CAGSA,SACTA,0CAGOiS,EAAQpf,MAChB8iB,gBACI1D,OAAc/a,OAAO4a,eAAejf,KACvC+iB,QAAQ,SAACxe,MACT2E,GAAQG,SAAS9E,EACnBqF,cAAaV,KAGJzB,KAAKyB,WAFT8Z,KAAK,IAAMze,EAAS,6BAKvBue,wFASH7c,EAAS2Z,KAAK4C,eACbC,WAAaxc,OACbA,OAASA,EAAS5C,eAAeuc,KAAKsC,eAGtCe,YAAc,iBAAMC,GAAKC,MAAK,IAC/BC,sBACEC,eAAiB,GAAID,gBAAexD,KAAKqD,kBACzCI,eAAeC,QAAQ1D,KAAK5U,gBAE3BgV,iBAAiB,SAAUJ,KAAKqD,oBAChCjD,iBAAiB,oBAAqBJ,KAAKqD,+CAI9CrD,KAAKyD,gBAAgBzD,KAAKyD,eAAeE,oBACtCC,oBAAoB,SAAU5D,KAAKqD,oBACnCO,oBAAoB,oBAAqB5D,KAAKqD,kDAKhDQ,qBACAC,mBACAhE,mBAEAyD,MAAK,GAAO,gDAKZnY,OAAOkL,UAAY,MAEpB3K,WACKqU,KAAK5U,iBACF,kBAGT4U,MAAK+D,qBACF1hB,QAAWiJ,MAAO0U,KAAK+D,iBAAmB,YAG3C1N,UAAY1V,EAAEwV,OAAO,MAAOxK,8CAI5BqY,IAAM,GAAIzE,gBACNS,KAAK3J,iBACL2J,KAAKR,cAETyE,+FAKDC,0DAAuBC,yDACvBD,IAAmBziB,SAASue,KAAK5U,eAIhC0Y,mBAEAM,KAAKF,QACLG,qBACAC,uBAEAC,WAAWpB,QAAQ,kBAAKjC,GAAErB,MAAMS,EAAKkE,iBAErCC,OAAOzE,KAAKuE,YAAY,GAE1BJ,SACG5W,KAAOyS,KAAK1C,oBACN,aAAYoH,OAAOpE,EAAK/S,OAASyS,KAAK+C,mBAG7C4B,oBAEAC,gBAAgBT,+EAMhBU,UAAYziB,uBAAuB4d,KAAK5U,aACxCE,MAAQ0U,KAAK6E,UAAYlhB,cAAcqc,KAAKsC,kDAI9CtC,KAAKlK,UACFO,UAAUrB,YAAYgL,KAAKlK,QAE7B1S,GAAI4c,KAAKsC,cAERxM,IAAM3K,iBACV6U,KAAK3J,UACL,qBACA2J,KAAK6E,UACL7E,KAAK6C,iBAEDtS,QAAUhF,YAAYyU,KAAKlK,KAE7BkK,KAAKE,MAAM/b,cACR2gB,QAAU/W,SACd,QACA3K,EAAEE,QAAQ/B,KACV6B,EAAEE,QAAQnC,IACV6e,KAAKE,gBAEM9c,EAAE2hB,mBACN,aACF3hB,EAAE2hB,oBAKL5jB,GAAMgC,aAAaC,QAClBohB,SAAW/Y,aACfuU,KAAK5f,KAAO,sCACCoD,cAAcJ,QAAOjC,OAGhC6e,KAAK3G,OAAOsJ,gBACP3C,KAAK3Z,OAASjD,EAAEG,SAAS1B,YAC3BmjB,WAAavZ,aACjB,4BACajI,cAAcJ,QAAOjC,QAIjC6e,KAAKE,MAAM/b,aAAe2R,IAAIvV,YAAYyf,KAAK8E,cAC7ChP,IAAIvV,YAAYyf,KAAKwE,UACvBxE,KAAK3G,OAAOsJ,iBAAmB7M,IAAIvV,YAAYyf,KAAKgF,iBAElDC,gBAAgBzhB,cAAcJ,GAAID,aAAaC,4CAGrCkJ,EAAGhG,QACb0d,IAAI/Y,UACLqB,IACAhG,kDAIoBie,WAAa,GAAIW,oCAEnC3X,GACFA,WACK6Q,MAAM,2BAEV7Q,KAAOyS,KAAKgC,YAAYzU,QACxB6W,YACAK,OAAOzE,KAAKuE,WAAYvE,KAAK3G,OAAO+I,cACpCuC,2DAGCJ,yDAAWvE,KAAKuE,WAAYnC,4DAC/BpC,MAAK3G,OAAO8I,kBAETa,SAASvY,IAAI,kBAAK/B,GAAE6B,WAAWyK,YAAYtM,QAG7CoM,QAEOqO,QAAQ,cACErO,EAAkBrQ,OAAOyc,EAAEwD,OAAOtC,MAEpDtN,EAAkB3Q,OAAS,oBACZ6b,KAAK3J,UAAW2J,KAAKlK,IAAKhB,cAChC,aACCqO,QAAQ,kBAAKjC,GAAEiE,WACrBC,aACH7G,gCAEQ4E,QAAQ,kBAAKjC,GAAEiE,cACrBC,iDAKHpF,KAAK3G,OAAO8I,mBACTf,mBACAiE,0GAMSlB,yDACXnE,MAAK3G,OAAO8I,aAEbgC,SACGmB,mBAEAC,eACEvF,KAAKwF,WAAWC,KAAKzF,SACrBA,KAAK0F,YAAYD,KAAKzF,SACtBA,KAAK2F,UAAUF,KAAKzF,SACpBA,KAAK4F,aAAaH,KAAKzF,SACvBA,KAAK6F,YAAYJ,KAAKzF,gBAGpBI,iBAAiB,UAAW,SAAC0F,GAClClkB,oBAAoBmkB,EAAK1P,eACvByP,GAAKhkB,OAAOkkB,MACbD,EAAKR,WAAWO,EAAEG,YACfV,WAAWO,EAAEG,mmBA2BlBC,GAAWrQ,iBAAiBmK,KAAKlK,kBACxBkK,KAAKE,OAAS,SAAUgG,4gBC3TlBC,wCACR/a,EAAQO,wHACbP,EAAQO,8EAGLA,gGACOA,QAEX0N,OAAO+M,gBAAkBza,EAAK0a,oBAAsBD,oBACpD/M,OAAOiN,UAAY3a,EAAK2a,WAAa,QACrCjN,OAAOkN,gBAAkB5a,EAAK4a,iBAAmB,6CAIlDC,EAAIxG,KAAK8C,MACTwD,EAAYtG,KAAK3G,OAAOiN,YAC1BG,kBAEEC,GAAY1G,KAAKzS,KAAKqP,OAAOnS,IAAI,SAACzD,EAAOY,MACxC+e,GAAQ,WACPpZ,KAAKuP,SAASrS,IAAI,eACbqb,EAAElL,OAAOhT,MAEX+e,EAAO3f,KACbkS,OAAO,kBAAcrV,GAAE,IAAM,IAE5B+iB,EAASF,KACVA,EAAUviB,OAASmiB,EAAW,GAEtBO,KAAK,SAAC7d,EAAGa,SAAeA,GAAE,GAAKb,EAAE,OAElC0d,EAAU5f,MAAM,EAAGwf,EAAU,MAGlCQ,GAAiB,CAFLJ,GAAU5f,MAAMwf,EAAU,GAGhC7b,IAAI,eAAwB5G,EAAE,OACjCgE,MAAMif,EAAgB,cACxBtH,OAAO8G,EAAU,GAAK,SAG1B1J,YACKnS,IAAI,cACRgc,YAAY5e,KAAKnC,MAAM7B,EAAE,OACzB+Y,OAAO/U,KAAKhE,EAAE,QAGfkjB,WAAaP,EAAEC,YAAY5d,OAAO,SAACG,EAAGa,SAAMb,GAAIa,GAAG,QAEhDqC,UACD8T,KAAK1U,MAAQ,IACb0U,KAAK3Z,OAAS,qDAKdmgB,EAAIxG,KAAK8C,WACRkC,WAAWgC,YAAc,QACzBC,aAAeT,EAAEC,YAAY3f,MAAM,EAAGkZ,KAAK3G,OAAOkN,oBAEnDtiB,GAAQ,EACRqC,EAAI,OACH2gB,aAAaxc,IAAI,SAAC5G,EAAG+D,MACrBsf,GAAW,IACXC,EAAU7iB,KAAK6C,OACjBigB,EAAK9b,MAAQ3H,cAAcyjB,EAAK9E,WAAW4E,EAEzCE,GAAKH,aAAa9iB,OAASgjB,MACnBC,EAAK9b,MAAM8b,EAAKH,aAAa9iB,QAEtCF,EAAQkjB,MACF,KACH,OAEF7a,GAAI4a,EAAWjjB,EAAQ,EACvB+C,EAAQogB,EAAK/N,OAAOgJ,gBAAkB1b,eAAe6f,EAAE5J,OAAOhV,GAAIsf,EAAS,IAAMV,EAAE5J,OAAOhV,GAC1F2Y,EAAY6G,EAAK/N,OAAO+M,eAAiBgB,EAAK/N,OAAO+M,eAAeviB,GAAKA,EACzEkM,EAAMjC,UACTxB,EACAhG,EACA,EACA8gB,EAAK5H,OAAO5X,GACTZ,OAAUuZ,GACb,KAEIyE,WAAWzkB,YAAYwP,gBApFe6R,WRJjCyF,kBAAoB,GACpB3P,mBAAqB,EAErBG,aAAe,IACfD,WAAa,MAEbM,aAAe,UAAW,WAAY,QAAS,QAAS,MACpE,OAAQ,OAAQ,SAAU,YAAa,UAAW,WAAY,YAIlDoP,iBAAmB,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,8rBCNpE/N,gDAEJgO,WAAAA,aAAa,SACbC,eAAAA,aAAiB,KACjB1O,IAAAA,UAEAC,IAAAA,QACA0O,IAAAA,aACAC,IAAAA,+CAEKF,eAAiBA,OACjB1O,UAAYA,OAEZ2O,aAAeA,OACf1O,QAAUA,OAEV2O,gBAAkBA,OAElBC,cACA/K,eAEA2K,WAAaA,OACbA,WAAyC,kBAArBvH,MAAKuH,WAC3BvH,KAAKuH,aAAevH,KAAKuH,gBAEvBxG,iEAGExT,QACFA,KAAOA,GAAQyS,KAAKjH,wCAGpB3N,QACAwc,MAAQnc,aAAauU,KAAKuH,WAAYvH,KAAKwH,eAAgBpc,uCAI3DqZ,OAAOzE,KAAKzS,WACZsa,QAAU7H,KAAKzS,oCAGdA,mBACDoa,MAAQ3H,KAAKyH,aAAala,QAE1Bqa,MAAMZ,YAAc,QACpBW,MAAMxE,QAAQ,cACbyE,MAAMrnB,YAAYS,UAEnB4b,OAAOuG,QAAQ,cACdyE,MAAMrnB,YAAYS,yCAIlBohB,mEACDrB,aACD2G,YACDtF,OACgBpC,KAAK0H,gBAAgB1H,KAAKzS,WAEtCma,WAILzO,0CAEU,qCACC1L,SACLA,GAAKua,aAAard,IAAI,SAAC+b,EAAG5e,MAC5Bd,GAAQ+E,SAAS2a,EAAG,aAAcjZ,EAAKiS,OAAO5X,GAAI,OAAQ2F,EAAKwa,sBAC7D7nB,MAAM8nB,WAAa,iBAClBlhB,8BAIOmhB,SACRjI,MAAK2H,MAAMld,IAAI,SAAC3D,EAAOc,SAAMuL,gBAAerM,EAAOmhB,EAAQH,aAAalgB,8BAIpE,mCACC2F,SACLA,GAAKua,aAAard,IAAI,SAAC+b,EAAG5e,MAC5Bd,GAAQ+E,SAAS2a,EAAG,WAAY,OAAQjZ,EAAKiS,OAAO5X,aAClD1H,MAAM8nB,WAAa,iBAClBlhB,8BAIOmhB,SACRjI,MAAK2H,MAAMld,IAAI,SAAC3D,EAAOc,SAC7BuL,gBAAerM,EAAOmhB,EAAQH,aAAalgB,mCAKjC,wCACC2F,oBACLA,GAAK2a,WAAWzd,IAAI,SAAC6B,EAAG1E,SAEpBsF,eAAcZ,EADhB,EACsBiB,EAAK4a,OAAOvgB,GACzC0Y,EAAKxH,UAAUsP,UAAW9H,EAAKxH,UAAUuP,SAAU9a,EAAKiS,OAAO5X,gCAKlDqgB,MACZA,EAAS,6BAID,+BACC1a,oBACLA,GAAK+a,UAAU7d,IAAI,SAAC8d,EAAU3gB,SACpCoH,OAAMuZ,EAAUhb,EAAKqP,OAAOhV,GAAIwf,EAAKtO,UAAUxN,OAC7C4D,KAAMkY,EAAKtO,UAAU5J,KAAMD,IAAKmY,EAAKtO,UAAU7J,IAAKF,eAAgBqY,EAAKtO,UAAU/J,6CAIvEkZ,MACXO,GAASP,EAAQK,UACjBG,EAAYR,EAAQrL,OACpB8L,EAAS1I,KAAK6H,QAAQS,UACtBK,EAAY3I,KAAK6H,QAAQjL,SAEVrW,qBAAqBmiB,EAAQF,+CACvBjiB,qBAAqBoiB,EAAWF,qDAEpDhE,kBACOiE,SACHD,IAGFzI,KAAK2H,MAAMld,IAAI,SAAC3C,EAAMF,SACrB0J,mBACNxJ,EAAM0gB,EAAO5gB,GAAI8gB,EAAO9gB,0BAOf,+BACC2F,oBACLA,GAAK+a,UAAU7d,IAAI,SAAC8d,EAAU3gB,SACpCwH,OAAMmZ,EAAUhb,EAAKqb,WAAWhhB,GAAIme,EAAKjN,UAAUzS,QACjD6I,KAAM6W,EAAKjN,UAAU5J,KAAMD,IAAK8W,EAAKjN,UAAU7J,kCAInCgZ,MACXO,GAASP,EAAQK,UACjBG,EAAYR,EAAQW,WACpBF,EAAS1I,KAAK6H,QAAQS,UACtBK,EAAY3I,KAAK6H,QAAQe,aAEVriB,qBAAqBmiB,EAAQF,+CACvBjiB,qBAAqBoiB,EAAWF,qDAEpDhE,kBACOiE,aACCD,IAGNzI,KAAK2H,MAAMld,IAAI,SAAC3C,EAAMF,SACrBsJ,mBACNpJ,EAAM0gB,EAAO5gB,GAAI8gB,EAAO9gB,6BAOf,kCACC2F,oBACLA,GAAK9C,IAAI,kBACf4E,SAAQjM,EAAEmlB,SAAUnlB,EAAE4D,MAAO6hB,EAAK/P,UAAUxN,OAC1CgE,SAAUlM,EAAE6K,QAAQqB,SAAUJ,KAAM,OAAQJ,SAAU,uCAG1CmZ,SACW1hB,qBAAqByZ,KAAK6H,QAASI,gCAAvDJ,gBAEFW,YAAiB/d,IAAI,kBAAK5G,GAAE0kB,WAC5BE,EAAYR,EAAQxd,IAAI,kBAAK5G,GAAEmD,QAC/B8hB,EAAab,EAAQxd,IAAI,kBAAK5G,GAAEoK,UAEhCya,EAAS1I,KAAK6H,QAAQpd,IAAI,kBAAK5G,GAAE0kB,uBAEhC9D,OAAOiE,EAAOje,IAAI,SAACwE,EAAKrH,mBAEjB8gB,EAAO9gB,SACV6gB,EAAU7gB,WACRkhB,EAAWlhB,OAIfoY,KAAK2H,MAAMld,IAAI,SAAC3C,EAAMF,SACrB0J,mBACNxJ,EAAM0gB,EAAO5gB,GAAI8gB,EAAO9gB,6BAOf,kCACC2F,oBACLA,GAAK9C,IAAI,kBACf+E,SAAQpG,EAAE2f,SAAU3f,EAAE4f,OAAQC,EAAKnQ,UAAUxN,MAC5ClC,EAAEpC,OAAQsI,SAAUlG,EAAE6E,QAAQqB,uCAGjB2Y,SACW1hB,qBAAqByZ,KAAK6H,QAASI,gCAAvDJ,gBAEFW,YAAiB/d,IAAI,kBAAK5G,GAAEmlB,SAC5BP,EAAYR,EAAQxd,IAAI,kBAAK5G,GAAEmD,QAC/BkiB,EAAYjB,EAAQxd,IAAI,kBAAK5G,GAAEklB,WAC/BD,EAAab,EAAQxd,IAAI,kBAAK5G,GAAEoK,UAEhCya,EAAS1I,KAAK6H,QAAQpd,IAAI,kBAAK5G,GAAEmlB,SACjCG,EAAYnJ,KAAK6H,QAAQpd,IAAI,kBAAK5G,GAAEklB,gBAEnCtE,OAAOiE,EAAOje,IAAI,SAACwE,EAAKrH,mBAEjBuhB,EAAUvhB,UACZ8gB,EAAO9gB,SACR6gB,EAAU7gB,WACRkhB,EAAWlhB,UAIlB8f,kBAECC,MAAMld,IAAI,SAACiH,EAAW9J,KACR8f,EAAgBjjB,OAAOgN,cACxCC,EAAWwX,EAAUthB,GAAI4gB,EAAO5gB,GAAI8gB,EAAO9gB,OAItC8f,2BAKI,iBAAoB,sBAAwB1H,KAAKlH,UAAUnJ,6BAC1DpC,gBACuDyS,KAAKlH,UAAnEnJ,IAAAA,MAAOyZ,IAAAA,SAAUC,IAAAA,UAAWC,IAAAA,WAAYvkB,IAAAA,OAEzCuH,IAFiDid,WAEjCjjB,EAAI,cAEnBkjB,0BAEAC,KAAKhf,IAAI,SAACif,EAAMC,GACN,IAAXA,KACG/M,OAAO/U,KACXkG,SAAS,cAAezB,GARL,GAQyByL,aAAapI,GAAO,GAAMia,wBAE1D,OAKTnf,IAAI,SAAC8N,EAAK3Q,MACX2Q,EAAI/T,KAAM,IACR+I,gBACUgL,EAAIsR,sBACHtR,EAAIuR,qBACNliB,GAETmiB,EAAS1c,WAAW,MAAOf,EAAGhG,EAAGgjB,EAAYvkB,EAAQwT,EAAI/T,KAAM+I,KAC9Dic,qBAAqB3hB,KAAKkiB,MAE3BV,MAEF,KACCD,IAGCpJ,KAAKwJ,+CAGGvB,MACZA,EAAS,gCAKD,iBAAoB,sCAAwCjI,KAAKlH,UAAUnJ,6BAC1EpC,MACR2T,GAAIlB,KAAKlH,sBACRkR,SAAW,WACXC,MAAQ1c,EAAK2c,WAAWzf,IAAI,SAACnE,EAAGrD,SAC7ByM,YACNnC,EAAK2a,WAAWjlB,GAChBqD,EACAiH,EAAK2Z,SACLhG,EAAE5X,MACFiE,EAAKqP,OAAO3Z,GACZA,EACAsK,EAAK4c,QAAQlnB,aAEFsK,EAAKnH,mBACJmH,EAAK6c,oBACLlJ,EAAErR,cAITmQ,KAAKiK,gCAEGhC,MACXoC,GAAUpC,EAAQC,WAClBoC,EAAUrC,EAAQiC,WAClBK,EAAatC,EAAQkC,QACrB1B,EAAYR,EAAQrL,OAEpB4N,EAAUxK,KAAK6H,QAAQK,WACvBuC,EAAUzK,KAAK6H,QAAQqC,WACvBQ,EAAa1K,KAAK6H,QAAQsC,QAC1BxB,EAAY3I,KAAK6H,QAAQjL,SAERrW,qBAAqBikB,EAASH,+CAC9B9jB,qBAAqBkkB,EAASH,+CACxB/jB,qBAAqBmkB,EAAYH,+CACnChkB,qBAAqBoiB,EAAWF,8CAEpDhE,mBACQ+F,aACAC,UACHC,SACDjC,WAEEzI,KAAK6H,QAAQzhB,mBACZ4Z,KAAK6H,QAAQuC,mBACdpK,KAAK6H,QAAQX,cAGpBQ,kBAECC,MAAMld,IAAI,SAAC0H,EAAKvK,KACF8f,EAAgBjjB,OAAOyN,WACxCC,EAAKkY,EAAQziB,GAAI0iB,EAAQ1iB,GAAIqgB,EAAQf,SAAUqD,EAAW3iB,IACzDxB,SAAU6hB,EAAQ7hB,cAIdshB,0BAKI,iBAAoB,sCAAwC1H,KAAKlH,UAAUnJ,6BAC1EpC,MACR2T,GAAIlB,KAAKlH,sBACRkR,SAAW,WACXxZ,SACD0Q,EAAEyJ,gBACAna,MAAQR,SACZzC,EAAK2a,WACL3a,EAAK2c,WACLhJ,EAAE5X,gBAES4X,EAAE7Q,oBACA6Q,EAAEzQ,kBACNyQ,EAAE/Q,iBAGD+Q,EAAE3Q,iBACDhD,EAAKnH,iBAKb6jB,SACD/I,EAAE0J,gBACAX,MAAQ1c,EAAK2c,WAAWzf,IAAI,SAACnE,EAAGrD,SAC7B6M,YACNvC,EAAK2a,WAAWjlB,GAChBqD,EACAiH,EAAKxI,OACLmc,EAAE5X,MACD4X,EAAE2J,iBAAmBtd,EAAKqN,OAAO3X,GAAK,GACvCA,MAKI+V,OAAO4B,OAAOoF,KAAKxP,OAAO/L,OAAOub,KAAKiK,iCAE9BhC,MACXoC,GAAUpC,EAAQC,WAClBoC,EAAUrC,EAAQiC,WAClBY,EAAY7C,EAAQrN,OAEpB4P,EAAUxK,KAAK6H,QAAQK,WACvBuC,EAAUzK,KAAK6H,QAAQqC,WACvBzW,EAAYuM,KAAK6H,QAAQjN,SAERrU,qBAAqBikB,EAASH,+CAC9B9jB,qBAAqBkkB,EAASH,+CAC1B/jB,qBAAqBkN,EAAWqX,8CAEpDrG,mBACQ+F,aACAC,SACJK,WAEE9K,KAAK6H,QAAQzhB,gBACf4Z,KAAK6H,QAAQ9iB,YAGlB2iB,YAED1O,QAAOxO,KAAKwV,KAAKxP,OAAOrM,WACRujB,EAAgBjjB,OAAOiO,YACxCsN,KAAKxP,MAAO6Z,EAASC,EAASrC,EAAQ7hB,SAAU4Z,KAAKlH,UAAU3I,UAG9D6P,KAAKiK,MAAM9lB,aACR8lB,MAAMxf,IAAI,SAACsF,EAAKnI,KACF8f,EAAgBjjB,OAAO8N,WACxCxC,EAAKsa,EAAQziB,GAAI0iB,EAAQ1iB,OAIrB8f,ggBQ3aWqD,uCACR3f,EAAQO,qHACbP,EAAQO,aACTvL,KAAO,eACPyf,kFAGM5R,MACP7K,GAAI4c,KAAKsC,cACR0I,WAAa/c,EAAQ+c,kBAEtBnhB,GAAImW,KAAKgL,aACX3kB,OAASwD,EAAExD,QAAUyY,gCACrB3R,MAAQtD,EAAEsD,OAASC,+BAEnB7J,SAAStB,MAAQ,KACjByB,aAAe,KACfmf,WAA0C,GAA5BhZ,EAAExD,OAAmB,GAAVwD,EAAEsD,oDAIzBqZ,GAAIxG,KAAK8C,MAET7J,IAEF,4BAEY+G,KAAKgL,WAAW3kB,gBACjB2Z,KAAKgL,WAAW7d,OAE3B,6BAEcqZ,EAAE0B,kBACN1B,EAAE2B,cACFnI,KAAKR,SAEbiG,KAAKzF,aAIJuE,WAAa,GAAIW,KAAIjM,EACxBxO,IAAI,eACAwgB,GAAYrS,6CAAgBjN,WACxBA,EAAK,GAAIsf,0IAMfzE,GAAIxG,KAAK8C,QAEXoF,gBACAC,aAEE+C,GAAO,IACTzE,YAAYhc,IAAI,SAAC5E,MACdyF,GAAQgV,EAAKhV,MAAQzF,EAAQ2gB,EAAEO,aACjCoB,OAAOtgB,KAAKyD,KACZ4c,WAAWrgB,KAAKqjB,MACV5f,gGAOLkb,EAAIxG,KAAK8C,WACRzM,UAAU+J,iBAAiB,YAAa,SAAC0F,MACzCqF,GAAO/D,EAAK7C,WAAW6G,IAAI,kBAAkBzD,MAC7CxV,EAAM2T,EAAEljB,UACTuoB,EAAKhS,SAAShH,GAAM,IAElBvK,GAAIujB,EAAK3P,QAAQrJ,GACjBkZ,EAAOtqB,UAAUqmB,EAAK/Q,WAAYiV,EAAOvqB,UAAUoR,GAEnD7F,EAAIgf,EAAK/pB,KAAO8pB,EAAK9pB,KAAOqI,SAASuI,EAAIF,aAAa,UAAU,EAChE3L,EAAIglB,EAAKnqB,IAAMkqB,EAAKlqB,IACpB+e,GAASkH,EAAKmE,iBAAmBnE,EAAKmE,gBAAgBpnB,OAAO,EAC9DijB,EAAKmE,gBAAgB3jB,GAAKwf,EAAKtE,MAAMlG,OAAOhV,IAAM,KACjD4jB,EAAWhF,EAAEC,YAAY7e,GAAG4e,EAAEO,aAE7B/C,IAAIyH,UAAUnf,EAAGhG,GAAIuS,KAAMqH,EAAOra,OAAiB,IAAT2lB,GAAc1nB,QAAQ,GAAK,QACrEkgB,IAAI0H,oBAlFgCvF,ihBCIxBwF,gCACRvgB,EAAQO,uHACbP,EAAQO,aACTvL,KAAO,QACP2iB,YAAc,IACdoB,KAAO,IAEPtE,oFAGIlU,gGACOA,QACXigB,UAAY5L,KAAK4L,UAAUnG,KAAKzF,WAChC6L,WAAa7L,KAAK6L,WAAWpG,KAAKzF,WAElC8L,WAAangB,EAAKmgB,YAAc,QAChCzS,OAAO0S,WAAapgB,EAAKogB,YAAc,OAEvC5f,UAAYR,EAAKQ,YAAa,wIAK/Bqa,GAAIxG,KAAK8C,WACR/d,OAAUib,KAAK3Z,OAAS2Z,KAAK1U,MAAQ0U,KAAK9T,OAAOI,EAAI0T,KAAK9T,OAAO5F,KAE9DvB,GAAsBib,KAAtBjb,OAAQoH,EAAc6T,KAAd7T,UAEV6f,EAAuBxF,EAAEyF,uBAC7BnE,kBACAmE,uBACEC,GAAW,IAAMlM,KAAK3G,OAAO0S,aAC/BtF,YAAYhc,IAAI,SAACkc,EAAO/e,MACnBmkB,GAAaG,EACbC,EAAmBxF,EAAQH,EAAEO,WAAczH,WAC3ClT,EAAW+f,EAAkB,IAAM,EAAG,EACtCC,EAAYjgB,GAAaggB,EAAkBA,EAC3CE,EAAWH,GAAsBE,EACjCpgB,EAAgBnH,mBAAmBknB,EAAYhnB,GAC/CkH,EAAcpH,mBAAmBwnB,EAAUtnB,GAE3CunB,EAAehM,EAAK6D,MAAQ6H,EAAqBpkB,GAEnD2kB,SAASC,QACVlM,GAAK6D,QACImI,EAAeA,EAAatgB,cAAgBA,IAC9CsgB,EAAeA,EAAargB,YAAcD,MAExCA,IACFC,MAEJwgB,GACe,MAApBN,EACGzf,cAAc6f,EAAUC,EAAQlM,EAAKpU,OAAQoU,EAAKvb,OAAQoH,EAAWC,GACrEL,eAAewgB,EAAUC,EAAQlM,EAAKpU,OAAQoU,EAAKvb,OAAQoH,EAAWC,KAExE0b,aAAajgB,KAAK4kB,KAClBR,iBAAiBpkB,0CAGX8e,QACAH,EAAEO,yCAGFqF,WAIJjI,KAAO,+CAIRqC,GAAIxG,KAAK8C,MAET7J,IAEF,eAEA,+BAEgBuN,EAAEsB,oBACR9H,KAAKR,SAEbiG,KAAKzF,aAIJuE,WAAa,GAAIW,KAAIjM,EACxBxO,IAAI,eACAwgB,GAAYrS,+CAAgBjN,WACxBA,EAAK,GAAIsf,kDAIAyB,MACb3nB,GAAqBib,KAArBjb,OAAO+mB,EAAc9L,KAAd8L,WACPvD,EAAW1jB,mBAAmB6nB,EAASX,WAAYW,EAAS5nB,MAAQ,EAAGC,wBACtDwjB,EAASjc,EAAKwf,QAAiBvD,EAASjiB,EAAKwlB,6CAG1D1b,EAAKxI,EAAE+kB,EAAK7G,MAClB1V,MACE9G,GAAQ0W,KAAKR,OAAO5X,MACvB+kB,EAAM,WACEvc,EAAM4P,KAAK4M,oBAAoB5M,KAAK8C,MAAMmJ,iBAAiBrkB,OAChE1H,MAAMsE,KAAO6E,mBAAmBC,EAAO,OACxCujB,GAAQ9rB,UAAUif,KAAKlK,KACvBxJ,EAAIwZ,EAAEgH,MAAQD,EAAMtrB,KAAO,GAC3B+E,EAAIwf,EAAEiH,MAAQF,EAAM1rB,IAAM,GAC1B+e,GAASF,KAAKgN,kBAAoBhN,KAAKgN,iBAAiB7oB,OAAS,EAClE6b,KAAKgN,iBAAiBplB,GAAKoY,KAAK8C,MAAMlG,OAAOhV,IAAM,KAClDqlB,GAAuC,IAA5BjN,KAAK8C,MAAM2D,YAAY7e,GAAWoY,KAAK8C,MAAMiE,YAAYjjB,QAAQ,QAC3EkgB,IAAIyH,UAAUnf,EAAGhG,GAAIuS,KAAMqH,EAAOra,MAAOonB,EAAU,WACnDjJ,IAAI0H,yBAECtb,EAAK,2BACV4T,IAAI/D,YACJ/f,MAAMsE,KAAO8E,8CAKd+M,UAAU+J,iBAAiB,YAAaJ,KAAK4L,gBAC7CvV,UAAU+J,iBAAiB,aAAcJ,KAAK6L,8CAG1C/F,MACHljB,GAASkjB,EAAEljB,OACbsqB,EAASlN,KAAKuE,WAAW6G,IAAI,aAAazD,MAC1CwF,EAAYnN,KAAKoN,oBACjBC,EAAarN,KAAKsN,kBACnBJ,EAAO/T,SAASvW,GAAS,IACvBgF,GAAIslB,EAAO1R,QAAQ5Y,QAClB2qB,WAAWF,EAAYF,GAAU,QACjCG,eAAiB1qB,OACjBwqB,oBAAsBxlB,OACtB2lB,WAAW3qB,EAAQgF,GAAG,EAAMke,aAE5B+F,uDAKD0B,WAAWvN,KAAKsN,eAAetN,KAAKoN,qBAAoB,UA/IzBjH,ysBCAhCqH,UAAYxO,oBAAsBC,oBAClCwO,WAAaD,UAGEE,+BACRtiB,EAAQ6C,uHACb7C,EAAQ6C,MACT7N,KAAO,YAEPutB,WAAa1f,EAAQ0f,YAAc,MAEpCC,IAAe,SAAU,UACzBC,EAAiBD,EAAYzU,SAASlL,EAAQ4f,gBAC/C5f,EAAQ4f,eAAiB,kBACvBC,oBAAsBF,EAAYpS,QAAQqS,KAE1ChO,sFAGM5R,MACP7K,GAAI4c,KAAKsC,cACRyL,gBAA8C,IAA5B9f,EAAQ8f,gBAAwB,EAAI,IAEzDxqB,SAASpC,IAAmB,EAAbssB,aACflqB,SAAS1B,OAAS,IAClB6B,aAA4B,EAAb+pB,aACf5K,WAAa4K,WAAa/V,mBACzBjU,eAAeL,MAEdS,GAAImc,KAAKzS,KACTygB,EAAUhO,KAAK+N,gBAAkB1G,kBAAoB,OACpDtD,kBAAoB5M,gBAAgBtT,EAAEK,MAAOL,EAAEuZ,KACjD4Q,GAAWR,UAAY7pB,cAAcP,4CAIpC4qB,GAAUhO,KAAK+N,gBAAkB1G,kBAAoB,EACrD4G,EAAYjO,KAAK8C,MAAMmL,UAAYjO,KAAK8C,MAAMmL,UAAY,QACzDpJ,WAAaoJ,EAAYD,GAAWR,UACtC7pB,cAAcqc,KAAKsC,mDAGX/U,0DAAKyS,KAAKzS,QAClBA,EAAKrJ,OAASqJ,EAAK6P,KAAO7P,EAAKrJ,MAAQqJ,EAAK6P,SACxC,IAAI0E,OAAM,kDAGbvU,EAAKrJ,UACHA,MAAQ,GAAI6B,QACZ7B,MAAMgqB,YAAa3gB,EAAKrJ,MAAMgT,cAAgB,IAEhD3J,EAAK6P,QAAYA,IAAM,GAAIrX,SAC1BooB,WAAa5gB,EAAK4gB,eAEpBvkB,SAASoP,OAAOxO,KAAK+C,EAAK4gB,YAAY,IAAM,IAAQ,IAClDxmB,aACG6C,KAAK+C,EAAK4gB,YAAYhL,QAAQ,eAChC3M,GAAO,GAAIzQ,MAAKqoB,EAAevW,gBAC5BhB,YAAYL,IAASjJ,EAAK4gB,WAAWC,OAExCD,WAAaxmB,QAGZ4F,qCAIHiZ,GAAIxG,KAAK8C,QAEX5e,MAAQ6R,MAAMiK,KAAKzS,KAAKrJ,SACxBkZ,IAAMrH,MAAMiK,KAAKzS,KAAK6P,OAEtBiR,eAAiBtY,MAAMyQ,EAAEtiB,SACzB+pB,UAAY9W,gBAAgBqP,EAAEtiB,MAAOsiB,EAAEpJ,OACvCZ,aAAeJ,iBAChBpD,OAAO4B,OAAOoF,KAAKzS,KAAK4gB,YAAapP,6BAEpCuP,cAAgBtO,KAAKuO,kEAInB/H,EAAIxG,KAAK8C,MACT0L,EAAUxO,KAAK+N,gBAAkB,EAAI,EAErC9U,EAAmBuN,EAAE8H,cAAc7jB,IAAI,SAAC4O,EAAQzR,UACnD,oBAEQyR,EAAO1J,eACJ6d,oBACCC,sBACCzO,2BACJsB,EAAKyB,aAAahd,QAAU,aACxByhB,EAAE8H,cACZpV,OAAO,SAACG,EAAQpW,SAAMA,GAAI2E,IAC1B6C,IAAI,kBAAU4O,GAAOoQ,KAAKtlB,OAASqqB,IACnC3lB,OAAO,SAACG,EAAGa,SAAMb,GAAIa,GAAG,GACvB2jB,WAEJ,iBACQhH,GAAE8H,cAAc1mB,IACtB6d,KAAKnF,WAIHiE,WAAa,GAAIW,KAAIjM,EACxBxO,IAAI,SAACkB,EAAM/D,MACPqjB,GAAYrS,+CAAgBjN,WACxBA,EAAK,GAAK,IAAM/D,EAAGqjB,SAIzB3kB,GAAI,kBACQ6c,QAAQ,SAACsL,EAAS7mB,OAC7B,EAAG,EAAG,GAAGuR,SAASvR,GAAI,IACrB8mB,GAAU3gB,SAAS,kBAAmByf,UAAU,EAAGlnB,EAAGmoB,YAE9CzP,uBACN,aACQ,UAGTwF,SAASjkB,YAAYmuB,MAEtBjB,4CAIAlgB,GACFA,WACK6Q,MAAM,2BAGV7Q,KAAOyS,KAAKgC,YAAYzU,QACxBgW,YACAU,oEAIA5N,UAAU+J,iBAAiB,YAAa,SAAC0F,KACxCvB,WAAWpB,QAAQ,eACnBwL,GAAaC,EAAKjH,MAClBkH,EAAY/I,EAAEljB,UACf+rB,EAAWxV,SAAS0V,GAAY,IAE9B5qB,GAAQ4qB,EAAU5c,aAAa,cAC/B6c,EAAYD,EAAU5c,aAAa,aAAaK,MAAM,KAEtD8F,EAAQL,aAAanO,SAASklB,EAAU,IAAI,GAAG,GAE/CzD,EAAOjE,EAAK/Q,UAAUnV,wBAAyBoqB,EAAOuD,EAAU3tB,wBAEhEoK,EAAQ1B,SAASkc,EAAEljB,OAAOqP,aAAa,UACvC3F,EAAIgf,EAAK/pB,KAAO8pB,EAAK9pB,KAAO+J,EAAM,EAClChF,EAAIglB,EAAKnqB,IAAMkqB,EAAKlqB,IACpB0E,EAAQ5B,EAAQ,IAAMmjB,EAAKuG,WAC3B9U,EAAO,OAAST,EAAQ,IAAM0W,EAAU,GAAK,KAAOA,EAAU,KAE7D9K,IAAIyH,UAAUnf,EAAGhG,GAAIuS,KAAMA,EAAMhT,MAAOA,EAAOib,WAAY,SAC3DkD,IAAI0H,sEAOP1G,WAAWgC,YAAc,MAC1B1a,GAAI,EACJhG,EAAImnB,WACJ1oB,EAASib,KAAK+B,aAAahd,QAAU,EAErCgqB,EAAWhhB,SAAS,iBAAkBzB,EAAGhG,EAAG,iBAEpC0Y,oBAAsB,KAC5B,MAGW,EAAZwO,UAAiBA,UAAU,OAC3BxI,WAAWzkB,YAAYwuB,QAEvBvP,OAAO1Y,MAAM,EAAGiY,2BAA2BtU,IAAI,SAACnB,EAAO1B,MACrDmiB,GAAS1c,WAAW,sBAAuBf,GAAKkhB,UAAY,GAAK5lB,EACtEtB,EAAG0Y,oBAAqBja,EAAQuE,KAC5B0b,WAAWzkB,YAAYwpB,QAIzBiF,GAAWjhB,SAAS,iBADRzB,EAAIyS,2BAA6ByO,UAAY,GAAKA,UAAU,EACvBlnB,EAAG,iBAE5C0Y,oBAAsB,KAC5B,SAGDgG,WAAWzkB,YAAYyuB,4CAaxB,GATAxI,GAAIxG,KAAK8C,SACoB0D,EAAEtiB,MAAM+S,WAAYuP,EAAEtiB,MAAMgT,eAAtD+X,OAAYC,UACU1I,EAAEpJ,IAAInG,WAAYuP,EAAEpJ,IAAIlG,eAE/CiY,OAAyBF,EAAa,EAA6B,SAAbC,GAExDZ,KAEAc,EAAerZ,MAAMyQ,EAAEtiB,OACnB0D,EAAI,EAAGA,EAAIunB,EAAYvnB,IAAK,IAC/ByP,GAAUmP,EAAEpJ,QACZtF,eAAesX,EAAc5I,EAAEpJ,KAAM,QACnBgS,EAAanY,WAAYmY,EAAalY,iBACjDiB,gCAEGtQ,KAAKmY,KAAKqP,gBAAgBD,EAAc/X,YAE9CA,EAAS,KACFA,QAGTiX,2CAGQlX,MAAWC,0DAAQ,MACbD,EAAUH,WAAYG,EAAUF,eAAhDkB,OAAOC,OACRiX,EAAc/X,eAAeH,GAG7BmY,SACInX,qBAHErC,MAAMsB,IAAYc,mBAAmBC,EAAOC,GAOrC,OAIb,GAHAmX,GAAiBrY,gBAAgBmY,EAAajY,GAE9CoS,KAAWjgB,SACP5B,EAAI,EAAGA,EAAI4nB,EAAgB5nB,MAC5BoY,KAAKyP,OAAOH,EAAalX,KAC1BvQ,KAAK2B,aAEI,GAAIzD,MAAKyD,EAAIkO,mBAAqB,GAAGmS,UAC9B,cAGuBrkB,KAA1CgE,EAAIkO,mBAAqB,GAAGoS,oBACtBwF,EAAa,KAChBznB,KAAKmY,KAAKyP,OAAOH,EAAalX,GAAO,OAG9BqR,KAAOA,EAEb8F,iCAGDnY,EAAWgB,OAOb,GAPoBsX,2DACpBlJ,EAAIxG,KAAK8C,MAGT6M,EAAc5Z,MAAMqB,GACpB5N,KAEI5B,EAAI,EAAGA,EAAI8P,mBAAoB9P,IAAK6Q,QAAQkX,EAAa,GAAI,IAChEtW,MAGAuW,EAAwBD,GAAenJ,EAAEtiB,OAASyrB,GAAenJ,EAAEpJ,GAEpEsS,IAASC,EAAY1Y,aAAemB,IAAUwX,IACzC/F,SAAWhT,YAAY8Y,KAErB3P,KAAK6P,mBAAmBF,KAE9B9nB,KAAKwR,SAGH7P,8CAGWgN,MACdqT,GAAWhT,YAAYL,GACvBsT,EAAY9J,KAAKzS,KAAK4gB,WAAWtE,mBAE1BA,YACCC,GAAa,OAClB9J,KAAKR,OAAO9C,iBAAiBoN,EAAW9J,KAAK8C,MAAMtG,uBAtRvBoF,0gBCFhB1D,iCACR9S,EAAQO,uHACbP,EAAQO,aAETqf,WAAarf,EAAKqf,iBAClB8E,YAAcnkB,EAAKmkB,kBAEnB1vB,KAAOuL,EAAKvL,MAAQ,SACpB+jB,KAAO,IAEPtE,wFAIFG,KAAKzS,KAAKuP,SAAS3Y,QAAU,SAC1BkV,OAAOsJ,WAAa,OACpBL,SAAS/e,SAAS1B,OAAS,sCAIxBoM,gGACOA,KAER8hB,YAAc9hB,EAAQ8hB,kBACtB1J,eAAiBpY,EAAQoY,wBAE5BhN,OAAO2W,UAAY/hB,EAAQ8hB,YAAYC,WAAa,YACpD3W,OAAO4W,UAAYhiB,EAAQ8hB,YAAYE,WAAa,YACpD5W,OAAO6W,UAAYjiB,EAAQ8hB,YAAYG,WAAa,OACpD7W,OAAO8W,oBAAsBliB,EAAQ8hB,YAAYI,qBAAuB,OAExE9W,OAAO+W,eAAiBniB,EAAQoY,eAAe+J,oBAC/C/W,OAAO+M,eAAiBnY,EAAQoY,eAAeD,oBAE/C/M,OAAOwR,iBAAmB5c,EAAQ4c,6DAIhClO,iEADSqD,KAAKzS,KACCyS,KAAK5f,uDAIpBid,qEADc2C,KAAKzS,wCAItB2W,gEACCmM,iBACDnM,QACEoM,oBAAoBtQ,KAAKuQ,gBAA+B,SAAdvQ,KAAK5f,WAEhDowB,8DAIDhK,GAAIxG,KAAK8C,MACTlG,EAASoD,KAAKzS,KAAKqP,SACrBC,cAAgBD,EAAOzY,SAEvBssB,UAAYzQ,KAAK1U,MAAOkb,EAAE3J,gBAE1B6T,QAAUlK,EAAEiK,UAAU,IAMtBE,cACO/T,YACGA,EAAOnS,IAAI,SAAC5G,EAAG+D,SACzBhE,UAAS4iB,EAAEkK,QAAU9oB,EAAI4e,EAAEiK,0DAKVG,MACbvV,GAAOV,mBAAmBiW,yDADa,SAEvC/U,EAAkBmE,KAAK3Z,OAASqV,cAAcL,GAC9CwV,EAAiBtV,gBAAgBF,GAAQQ,EACzCzV,EAAW4Z,KAAK3Z,OAAU+U,aAAaC,GAAQwV,OAEhD/N,MAAMlH,cACFP,YACGA,EAAK5Q,IAAI,kBAAKrE,GAAWvC,EAAIgY,oBACvBA,WACPzV,QAIN0qB,yBACAC,qBACAC,8DAIDxK,GAAIxG,KAAK8C,MACTmO,EAAW,kBAAUrW,GAAOnQ,IAAI,kBAAOkR,OAAMrR,EAAKkc,EAAE5K,YAEtDkB,SAAWkD,KAAKzS,KAAKuP,SAASrS,IAAI,SAAC5G,EAAG+D,MACnCgT,GAAS/W,EAAE+W,OACXsW,EAAertB,EAAEqtB,6BAEdrtB,EAAEgV,MAAQhV,EAAEgV,KAAKsY,QAAQ,SAAU,SAACC,SAAiB,KAARA,EAAc,QAAkB,KAARA,EAAc,OAAS,eAC3FxpB,YACI/D,EAAEoZ,iBAELrC,aACIqW,EAASrW,gBAEPsW,iBACED,EAASC,iDAMvB1K,GAAIxG,KAAK8C,SACV9C,KAAKgL,WAAWqG,sBAChBC,UAAY9K,EAAE1J,SAAS0J,EAAE1J,SAAS3Y,OAAS,GAAGotB,kBAG/CD,UAAY,GAAIjtB,OAAMmiB,EAAE3J,eAAerY,KAAK,QAC5CsY,SAASrS,IAAI,cACZyf,WAAWzf,IAAI,SAACwE,EAAKhM,GACnBgM,EAAMuX,EAAE8K,UAAUruB,OAClBquB,UAAUruB,GAAKgM,iDAOhBuX,GAAIxG,KAAK8C,KACV9C,MAAKzS,KAAKiQ,gBACPsF,MAAMtF,SAAWwC,KAAKzS,KAAKiQ,SAAS/S,IAAI,qBAC1C8d,SAAW5M,MAAM9X,EAAEgC,MAAO2gB,EAAE5K,OAC1B/X,EAAEoK,UAASpK,EAAEoK,YAIVpK,KAGNmc,KAAKzS,KAAK4P,gBACP2F,MAAM3F,SAAW6C,KAAKzS,KAAK4P,SAAS1S,IAAI,qBAC1Cse,SAAWpN,MAAM9X,EAAEK,MAAOsiB,EAAE5K,SAC5BoN,OAASrN,MAAM9X,EAAEuZ,IAAKoJ,EAAE5K,OACtB/X,EAAEoK,UAASpK,EAAEoK,YACVpK,0DAMLiC,EAAM,YAEPka,KAAKgL,WAAWqG,QAAS,GACrB,kBACFG,GAAa,GAAIntB,OAAM2b,KAAK8C,MAAMjG,eAAerY,KAAK,QACrD+I,KAAKuP,SAASrS,IAAI,SAAC5G,EAAG+D,MACtBgT,GAAS0F,EAAK/S,KAAKuP,SAASlV,GAAGgT,SACjC9U,GAAO0rB,EAAaA,EAAW/mB,IAAI,SAACyW,EAAGtZ,SAAMsZ,GAAItG,EAAOhT,UAIxD6pB,GAAgBzR,KAAKzS,KAAKuP,SAASrS,IAAI,kBAAK5G,GAAEiC,WAC/Cka,MAAKzS,KAAKiQ,YACE3V,KAAKmY,KAAKzS,KAAKiQ,SAAS/S,IAAI,kBAAK5G,GAAEgC,SAE/Cma,KAAKzS,KAAK4P,eACP5P,KAAK4P,SAAS1S,IAAI,cACR5C,MAAMhE,EAAEuZ,IAAKvZ,EAAEK,iBAIrBO,oCAAUgtB,yDAIhBxY,IAEF,cAEO+G,KAAK3G,OAAO4W,gBACXjQ,KAAK1U,qBACI0U,KAAK3G,OAAO8W,qBAG7B,iBACQnQ,MAAK8C,MAAMlH,OACjB6J,KAAKzF,QAIP,cAEOA,KAAK3G,OAAO2W,iBACVhQ,KAAK3Z,QAGd,cACKmgB,GAAIxG,KAAK8C,eACX6N,MAAM/H,WAAanL,mBAAmBuC,KAAK1U,MAC5Ckb,EAAEmK,MAAM/T,OAAQoD,KAAK3G,OAAO6W,WAEtB1J,EAAEmK,OACRlL,KAAKzF,QAIP,kBAEQA,KAAK1U,UACP,SAEN,iBACQ0U,MAAK8C,MAAM3F,UACjBsI,KAAKzF,QAIL0R,EAAc1R,KAAK8C,MAAMhG,SAAS5D,OAAO,kBAAqB,QAAhBrV,EAAEoZ,YAChD0U,EAAe3R,KAAK8C,MAAMhG,SAAS5D,OAAO,kBAAqB,SAAhBrV,EAAEoZ,YAEjD2U,EAAcF,EAAYjnB,IAAI,eAC7BkF,GAAQ9L,EAAE8L,aAEb,YAAmB9L,EAAE8L,aAEbA,QACAyX,EAAK5H,OAAO7P,WACVyX,EAAK4D,WAAWqG,yBAGPjK,EAAK/N,OAAOwR,2BACnBzD,EAAK/gB,OAASsY,wBAE1B,cACK6H,GAAIxG,KAAK8C,MACTjf,EAAI2iB,EAAE1J,SAASnN,GACf0hB,EAAUrR,KAAKgL,WAAWqG,QAE1BQ,EAAa7R,KAAKgL,WAAW6G,YAAcnT,sBAC3C0L,EAAY5D,EAAEiK,WAAa,EAAIoB,GAC/B3K,EAAWkD,GAAWiH,EAAU,EAAIK,EAAYvtB,QAEhD+jB,EAAa1B,EAAEmK,MAAMrI,UAAU7d,IAAI,kBAAK6B,GAAI8d,EAAU,GACtDiH,OACUnJ,EAAWzd,IAAI,kBAAKvD,GAAIggB,EAAWvX,QAG7CiN,GAAS,GAAIvY,OAAMmiB,EAAE3J,eAAerY,KAAK,GAC1Cwb,MAAK3G,OAAOwR,qBACXwG,GAAWxtB,EAAE8L,QAAU6W,EAAE1J,SAAS3Y,OAAS,EACpCN,EAAEqtB,aAEFrtB,EAAE+W,WAITuP,GAAU,GAAI9lB,OAAMmiB,EAAE3J,eAAerY,KAAK,SAC3C6sB,OACQxtB,EAAEqmB,WAAWzf,IAAI,SAACnE,EAAGrD,SAAMqD,GAAIzC,EAAE0tB,eAAetuB,kBAI9CilB,aACArkB,EAAEqmB,mBACLC,SAEDvN,WAEE4J,EAAE5K,MAAMxV,mBACPgkB,WACDlD,IAEVzB,KAAK2B,MAIL0K,EAAcH,EAAalnB,IAAI,eAC9BkF,GAAQ9L,EAAE8L,aAEb,aAAoB9L,EAAE8L,aAEdA,QACAyX,EAAK5H,OAAO7P,WACVyX,EAAK7W,iBACJ6W,EAAK0I,YAAYzf,oBACf+W,EAAK0I,YAAYrf,kBACrB2W,EAAK0I,YAAY3f,gBACfiX,EAAK0I,YAAYlF,kBACjBxD,EAAK0I,YAAYnF,0BAGTvD,EAAK/N,OAAOwR,kBAE/B,cACKrE,GAAIxG,KAAK8C,MACTjf,EAAI2iB,EAAE1J,SAASnN,GACfoiB,EAAUvL,EAAE5K,MAAM0M,UAAU,GAAK9B,EAAE5K,MAAMxV,SAC1CogB,EAAE5K,MAAM0M,UAAU,GAAK9B,EAAE5K,MAAMxV,2BAGrBogB,EAAEmK,MAAMrI,qBACRzkB,EAAEqmB,kBAENrmB,EAAE+W,gBAEAmX,SACF/R,KAAK8P,YAAYkC,SAAWpT,sBAEpC6G,KAAK2B,MAIL6K,IAEF,kBAEQjS,KAAK1U,UACP,SAEN,iBACQ0U,MAAK8C,MAAMtF,UACjBiI,KAAKzF,UAIU/G,EAAiBxU,OAAOmtB,EAAaE,EAAaG,MAEjEC,IAAa,WAAY,iBACxBC,2BAEA5N,WAAa,GAAIW,KAAIjM,EACxBC,OAAO,mBAASgZ,EAAU/Y,SAASxN,EAAK,KAAOyb,EAAKtE,MAAMnX,EAAK,MAC/DlB,IAAI,eACAwgB,GAAYrS,+CAAgBjN,WAC7BA,EAAK,GAAGwN,SAAS,cAAgBxN,EAAK,GAAGwN,SAAS,gBAC/CgZ,mBAAmBtqB,KAAKojB,IAEtBtf,EAAK,GAAIsf,gEAKdmH,kBAED5L,GAAIxG,KAAK8C,MACTuP,EAAUrS,KAAK3G,OAAO+W,eACtBkC,EAAUtS,KAAK3G,OAAO+M,cACbI,GAAEmK,MAAM/T,OAEdnS,IAAI,SAACzD,EAAO2I,MACdiL,GAASmL,EAAKjD,MAAMhG,SAASrS,IAAI,SAAC4V,EAAKzY,MACtC/B,GAAQwa,EAAIzF,OAAOjL,gBAEf0Q,EAAIxH,WACJhT,OACDwa,EAAI6J,WAAWva,SACdoW,EAAKvG,OAAO5X,aACR0qB,EAAUA,EAAQzsB,GAASA,OAInCusB,YAAYziB,UACT3I,iBACSqrB,EAAUA,EAAQrrB,GAASA,OACrCwf,EAAEmK,MAAMrI,UAAU3Y,UAChBiL,WACE4L,EAAE8K,UAAU3hB,4DAOnB0G,UAAU+J,iBAAiB,YAAa,SAAC0F,MACzC1iB,GAAIylB,EAAKvG,SACT5Z,EAAI3H,UAAU8nB,EAAKxS,WACnBkc,EAAOzM,EAAEgH,MAAQpkB,EAAEnH,KAAOiC,cAAcJ,GACxCovB,EAAO1M,EAAEiH,MAAQrkB,EAAEvH,GAEpBqxB,GAAO3J,EAAKxiB,OAASlD,aAAaC,IACjCovB,EAAQrvB,aAAaC,KACnBqvB,oBAAoBF,KAEpBvO,IAAI/D,wDAKQsS,MACf/L,GAAIxG,KAAK8C,SACT0D,EAAE8K,cAEF3hB,GAAQmM,kBAAkByW,EAAM/L,EAAEmK,MAAMrI,WAAW,MACnD3Y,GAAS,EAAG,IACX+iB,GAAM1S,KAAKoS,YAAYziB,QAEtBqU,IAAIyH,UACRiH,EAAIxH,KAAOlL,KAAKgE,IAAI/Y,OAAOqB,EAC3BomB,EAAIC,SAAW3S,KAAKgE,IAAI/Y,OAAO3E,GAC9BuS,KAAM6Z,EAAIE,eAAgB/sB,MAAO,IAClC6sB,EAAI9X,OACJjL,QAGIqU,IAAI0H,8DAKNlF,EAAIxG,KAAKzS,IACViZ,GAAE1J,SAAS3Y,OAAS,SACjB6gB,WAAWgC,YAAc,KAC5BlK,SAASrS,IAAI,SAAC5G,EAAG+D,MACdsf,GAAWzI,qBAGXxd,EAAOuM,YAEC5F,EACX,IACAsf,EACA+B,EAAKzJ,OAAO5X,GACZ/D,EAAEgV,KACFoQ,EAAK5P,OAAOgJ,mBACR2C,WAAWzkB,YAAYU,0DAS3B+e,KAAKmE,sBACFA,KAAO,EAGVnE,MAAK6S,oBACFA,cAAc1P,QAAQ,eACtBza,GAAIoB,EAAEwX,UACR/W,WAAWyK,YAAYtM,UAItBmqB,cAAgB7S,KAAKmS,mBAAmB1nB,IAAI,wBAEzCyW,EAAE8I,qBACCxkB,SACF0b,EAAE+I,aAIoBzkB,KAA5Bwa,KAAK8C,MAAMgQ,oBACRhQ,MAAMgQ,aAAe9S,KAAK8C,MAAMjG,cAAgB,QAIjDgW,cAAcpoB,IAAI,eAClBsoB,GAAclvB,EAAEomB,MAAM+I,EAAKlQ,MAAMgQ,gBAEnCxR,QAAUF,YAAYvd,EAAEzD,MAAM2yB,KAC3BvO,SAASjkB,YAAYsD,EAAEyd,yDAK1BtB,KAAK6S,oBACFA,cAAc1P,QAAQ,eACtBza,GAAIoB,EAAEwX,UACR/W,WAAWyK,YAAYtM,2DAMtB0C,OAAOgV,iBAAiB,cAAe,aACtCmB,sEAKD4Q,mBAAmB1nB,IAAI,cACzBwf,MAAMxf,IAAI,cACN2V,iBAAiB,QAAS,cAC1BzQ,GAAQiB,EAAKqB,aAAa,sBACzBghB,oBAAoBtjB,cAMvBqU,IAAI3N,UAAU+J,iBAAiB,QAAS,cACxCzQ,GAAQujB,EAAKlP,IAAI3N,UAAUpE,aAAa,sBACvCghB,oBAAoBtjB,6DAKrBkjB,cAAcpoB,IAAI,eAClBsoB,GAAclvB,EAAEomB,MAAMkJ,EAAKrQ,MAAMgQ,4BACvBjvB,EAAEzD,MAAM2yB,EAAalvB,EAAEyd,sDAKjC2R,oBAAoBjT,KAAK8C,MAAMgQ,aAAe,+CAI9CG,oBAAoBjT,KAAK8C,MAAMgQ,aAAe,6CAGvCnjB,0DAAMqQ,KAAK8C,MAAMgQ,aACzBtM,EAAIxG,KAAK8C,mBAELnT,QACA6W,EAAEmK,MAAM/T,OAAOjN,UACd6W,EAAE1J,SAASrS,IAAI,kBAAK5G,GAAE+W,OAAOjL,kDAKnBA,MACf6W,GAAIxG,KAAK8C,SACLlZ,SAAS+F,IACN,IAAGA,EAAQ,GACnBA,GAAS6W,EAAEmK,MAAM/T,OAAOzY,SAAQwL,EAAQ6W,EAAEmK,MAAM/T,OAAOzY,OAAS,GAChEwL,IAAU6W,EAAEsM,iBACbA,aAAenjB,OACZqQ,KAAK5U,OAAQ,cAAe4U,KAAKoT,sDAM1BpsB,EAAOqsB,MAAe1jB,0DAAMqQ,KAAK8C,MAAMjG,8GAChC7V,EAAOqsB,EAAe1jB,QACpCpC,KAAKqP,OAAO0W,OAAO3jB,EAAO,EAAG3I,QAC7BuG,KAAKuP,SAASrS,IAAI,SAAC5G,EAAG+D,KACxBgT,OAAO0Y,OAAO3jB,EAAO,EAAG0jB,EAAczrB,WAEpC8c,OAAO1E,KAAKzS,mDAGFoC,0DAAQqQ,KAAK8C,MAAMjG,cAAc,CAC5CmD,MAAKzS,KAAKqP,OAAOzY,QAAU,uGAGTwL,QACjBpC,KAAKqP,OAAO0W,OAAO3jB,EAAO,QAC1BpC,KAAKuP,SAASrS,IAAI,cACpBmQ,OAAO0Y,OAAO3jB,EAAO,UAEnB+U,OAAO1E,KAAKzS,6CAGJ8lB,MAAe1jB,0DAAM,OAC7BpC,KAAKuP,SAASnN,GAAOiL,OAASyY,OAC9B3O,OAAO1E,KAAKzS,6CAKHuP,QACTvP,KAAKuP,SAASrS,IAAI,SAAC5G,EAAG+D,GACvBkV,EAASlV,OACTgT,OAASkC,EAASlV,WAGjB8c,OAAO1E,KAAKzS,aA5jBoBqU,0gBCFlB2R,kCACRnoB,EAAQO,uHACbP,EAAQO,aACTvL,KAAO,UACP2iB,YAAc,IACdoB,KAAO,IAEPtE,oFAGIlU,gGACOA,QACXigB,UAAY5L,KAAK4L,UAAUnG,KAAKzF,WAChC6L,WAAa7L,KAAK6L,WAAWpG,KAAKzF,WAElC8L,WAAangB,EAAKmgB,YAAc,QAChCzS,OAAO0S,WAAapgB,EAAKogB,YAAc,OAEvC5f,UAAYR,EAAKQ,YAAa,OAC9B4b,YAAcpc,EAAKoc,aAAe,yIAKnCvB,GAAIxG,KAAK8C,WACR/d,OACJib,KAAK3Z,OAAS2Z,KAAK1U,MAChB0U,KAAK9T,OAAOI,EAAI0T,KAAK+H,YAAc,EACnC/H,KAAK9T,OAAO5F,EAAI0Z,KAAK+H,YAAc,KAE/BhjB,GAAsBib,KAAtBjb,OAAQoH,EAAc6T,KAAd7T,UAEV6f,EAAuBxF,EAAEyF,uBAC7BnE,kBACAmE,uBACEC,GAAW,IAAMlM,KAAK3G,OAAO0S,aAE/BtF,YAAYhc,IAAI,SAACkc,EAAO/e,MACnBmkB,GAAaG,EACbC,EAAmBxF,EAAQH,EAAEO,WAAczH,WAC3ClT,EAAW+f,EAAkB,IAAM,EAAG,EACtCC,EAAYjgB,GAAaggB,EAAkBA,EAC3CE,EAAWH,GAAsBE,EACjCpgB,EAAgBnH,mBAAmBknB,EAAYhnB,GAC/CkH,EAAcpH,mBAAmBwnB,EAAUtnB,GAE3CunB,EAAehM,EAAK6D,MAAQ6H,EAAqBpkB,GAEnD2kB,SAASC,QACVlM,GAAK6D,QACImI,EAAeA,EAAatgB,cAAgBA,IAC9CsgB,EAAeA,EAAargB,YAAcD,MAExCA,IACFC,MAEJwgB,GACe,MAApBN,EACGtf,oBAAoB0f,EAAUC,EAAQlM,EAAKpU,OAAQoU,EAAKvb,OAAQub,EAAKnU,UAAWC,GAChFQ,qBAAqB2f,EAAUC,EAAQlM,EAAKpU,OAAQoU,EAAKvb,OAAQub,EAAKnU,UAAWC,KAEnF0b,aAAajgB,KAAK4kB,KAClBR,iBAAiBpkB,0CAGX8e,QACAH,EAAEO,yCAGFqF,WAIJjI,KAAO,+CAIRqC,GAAIxG,KAAK8C,MAET7J,IAEF,iBAEA,+BAEgBuN,EAAEsB,oBACR9H,KAAKR,mBACAQ,KAAK+H,cAElBtC,KAAKzF,aAIJuE,WAAa,GAAIW,KAAIjM,EACxBxO,IAAI,eACAwgB,GAAYrS,+CAAgBjN,WACxBA,EAAK,GAAIsf,kDAIAyB,MACZ3nB,GAAuBib,KAAvBjb,OAAQ+mB,EAAe9L,KAAf8L,WACTvD,EAAW1jB,mBAAmB6nB,EAASX,WAAYW,EAAS5nB,MAAQ,EAAGC,wBACtDwjB,EAASjc,EAAKwf,QAAiBvD,EAASjiB,EAAKwlB,6CAG1D1b,EAAKxI,EAAE+kB,EAAK7G,MAClB1V,MACE9G,GAAQ0W,KAAKR,OAAO5X,MACvB+kB,EAAM,WACEvc,EAAM4P,KAAK4M,oBAAoB5M,KAAK8C,MAAMmJ,iBAAiBrkB,OAChE1H,MAAMsO,OAASnF,mBAAmBC,EAAO,OAC1CujB,GAAQ9rB,UAAUif,KAAKlK,KACvBxJ,EAAIwZ,EAAEgH,MAAQD,EAAMtrB,KAAO,GAC3B+E,EAAIwf,EAAEiH,MAAQF,EAAM1rB,IAAM,GAC1B+e,GAASF,KAAKgN,kBAAoBhN,KAAKgN,iBAAiB7oB,OAAS,EAClE6b,KAAKgN,iBAAiBplB,GAAKoY,KAAK8C,MAAMlG,OAAOhV,IAAM,KAClDqlB,GAAuC,IAA5BjN,KAAK8C,MAAM2D,YAAY7e,GAAWoY,KAAK8C,MAAMiE,YAAYjjB,QAAQ,QAC3EkgB,IAAIyH,UAAUnf,EAAGhG,GAAIuS,KAAMqH,EAAOra,MAAOonB,EAAU,WACnDjJ,IAAI0H,yBAECtb,EAAK,2BACV4T,IAAI/D,YACJ/f,MAAMsO,OAASlF,8CAKhB+M,UAAU+J,iBAAiB,YAAaJ,KAAK4L,gBAC7CvV,UAAU+J,iBAAiB,aAAcJ,KAAK6L,8CAG1C/F,MACHljB,GAASkjB,EAAEljB,OACbsqB,EAASlN,KAAKuE,WAAW6G,IAAI,eAAezD,MAC5CwF,EAAYnN,KAAKoN,oBACjBC,EAAarN,KAAKsN,kBACnBJ,EAAO/T,SAASvW,GAAS,IACvBgF,GAAIslB,EAAO1R,QAAQ5Y,QAClB2qB,WAAWF,EAAYF,GAAU,QACjCG,eAAiB1qB,OACjBwqB,oBAAsBxlB,OACtB2lB,WAAW3qB,EAAQgF,GAAG,EAAMke,aAE5B+F,uDAKD0B,WAAWvN,KAAKsN,eAAetN,KAAKoN,qBAAoB,UArJvBjH,kBTAlChI,gBACAD,eACCA,qBAEM6M,wBACH2C,YACJ/B,eACE4H,YAiBFC,MACL,WAAYpoB,EAAQ6C,kCACZgQ,eAAehQ,EAAQ7N,KAAMgL,EAAQ6C"} \ No newline at end of file diff --git a/node_modules/frappe-charts/dist/frappe-charts.min.umd.js b/node_modules/frappe-charts/dist/frappe-charts.min.umd.js deleted file mode 100644 index 9d213b9..0000000 --- a/node_modules/frappe-charts/dist/frappe-charts.min.umd.js +++ /dev/null @@ -1,2 +0,0 @@ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):t.frappe=e()}(this,function(){"use strict";function t(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function e(t){var e=t.getBoundingClientRect();return{top:e.top+(document.documentElement.scrollTop||document.body.scrollTop),left:e.left+(document.documentElement.scrollLeft||document.body.scrollLeft)}}function i(t){return null===t.offsetParent}function n(t){var e=t.getBoundingClientRect();return e.top>=0&&e.left>=0&&e.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&e.right<=(window.innerWidth||document.documentElement.clientWidth)}function a(t){var e=window.getComputedStyle(t),i=parseFloat(e.paddingLeft)+parseFloat(e.paddingRight);return t.clientWidth-i}function s(t,e,i){var n=document.createEvent("HTMLEvents");n.initEvent(e,!0,!0);for(var a in i)n[a]=i[a];return t.dispatchEvent(n)}function r(t){return t.titleHeight+t.margins.top+t.paddings.top}function o(t){return t.margins.left+t.paddings.left}function l(t){return t.margins.top+t.margins.bottom+t.paddings.top+t.paddings.bottom+t.titleHeight+t.legendHeight}function u(t){return t.margins.left+t.margins.right+t.paddings.left+t.paddings.right}function h(t){return parseFloat(t.toFixed(2))}function c(t,e,i){var n=arguments.length>3&&void 0!==arguments[3]&&arguments[3];i||(i=n?t[0]:t[t.length-1]);var a=new Array(Math.abs(e)).fill(i);return t=n?a.concat(t):t.concat(a)}function d(t,e){return(t+"").length*e}function p(t,e){return{x:Math.sin(t*Zt)*e,y:Math.cos(t*Zt)*e}}function f(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1];return!Number.isNaN(t)&&(void 0!==t&&(!!Number.isFinite(t)&&!(e&&t<0)))}function v(t){return Number(Math.round(t+"e4")+"e-4")}function g(t){var e=void 0,i=void 0,n=void 0;if(t instanceof Date)return new Date(t.getTime());if("object"!==(void 0===t?"undefined":Ft(t))||null===t)return t;e=Array.isArray(t)?[]:{};for(n in t)i=t[n],e[n]=g(i);return e}function m(t,e){var i=void 0,n=void 0;return t<=e?(i=e-t,n=t):(i=t-e,n=e),[i,n]}function y(t,e){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:e.length-t.length;return i>0?t=c(t,i):e=c(e,i),[t,e]}function b(t,e){if(t)return t.length>e?t.slice(0,e-3)+"...":t}function x(t){var e=void 0;if("number"==typeof t)e=t;else if("string"==typeof t&&(e=Number(t),Number.isNaN(e)))return t;var i=Math.floor(Math.log10(Math.abs(e)));if(i<=2)return e;var n=Math.floor(i/3),a=Math.pow(10,i-3*n)*+(e/Math.pow(10,i)).toFixed(1);return Math.round(100*a)/100+" "+["","K","M","B","T"][n]}function k(t,e){for(var i=[],n=0;n255?255:t<0?0:t}function A(t,e){var i=ie(t),n=!1;"#"==i[0]&&(i=i.slice(1),n=!0);var a=parseInt(i,16),s=w((a>>16)+e),r=w((a>>8&255)+e),o=w((255&a)+e);return(n?"#":"")+(o|r<<8|s<<16).toString(16)}function P(t){var e=/(^\s*)(rgb|hsl)(a?)[(]\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*(?:,\s*([\d.]+)\s*)?[)]$/i;return/(^\s*)(#)((?:[A-Fa-f0-9]{3}){1,2})$/i.test(t)||e.test(t)}function T(t,e){return"string"==typeof t?(e||document).querySelector(t):t||null}function L(t,e){var i=document.createElementNS("http://www.w3.org/2000/svg",t);for(var n in e){var a=e[n];if("inside"===n)T(a).appendChild(i);else if("around"===n){var s=T(a);s.parentNode.insertBefore(i,s),i.appendChild(s)}else"styles"===n?"object"===(void 0===a?"undefined":Ft(a))&&Object.keys(a).map(function(t){i.style[t]=a[t]}):("className"===n&&(n="class"),"innerHTML"===n?i.textContent=a:i.setAttribute(n,a))}return i}function O(t,e){return L("linearGradient",{inside:t,id:e,x1:0,x2:0,y1:0,y2:1})}function M(t,e,i,n){return L("stop",{inside:t,style:"stop-color: "+i,offset:e,"stop-opacity":n})}function C(t,e,i,n){return L("svg",{className:e,inside:t,width:i,height:n})}function D(t){return L("defs",{inside:t})}function N(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0,n={className:t,transform:e};return i&&(n.inside=i),L("g",n)}function S(t){return L("path",{className:arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",d:t,styles:{stroke:arguments.length>2&&void 0!==arguments[2]?arguments[2]:"none",fill:arguments.length>3&&void 0!==arguments[3]?arguments[3]:"none","stroke-width":arguments.length>4&&void 0!==arguments[4]?arguments[4]:2}})}function E(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,r=i.x+t.x,o=i.y+t.y,l=i.x+e.x,u=i.y+e.y;return"M"+i.x+" "+i.y+"\n\t\tL"+r+" "+o+"\n\t\tA "+n+" "+n+" 0 "+s+" "+(a?1:0)+"\n\t\t"+l+" "+u+" z"}function _(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,r=i.x+t.x,o=i.y+t.y,l=i.x+e.x,u=2*i.y,h=i.y+e.y;return"M"+i.x+" "+i.y+"\n\t\tL"+r+" "+o+"\n\t\tA "+n+" "+n+" 0 "+s+" "+(a?1:0)+"\n\t\t"+l+" "+u+" z\n\t\tL"+r+" "+u+"\n\t\tA "+n+" "+n+" 0 "+s+" "+(a?1:0)+"\n\t\t"+l+" "+h+" z"}function z(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,r=i.x+t.x,o=i.y+t.y,l=i.x+e.x,u=i.y+e.y;return"M"+r+" "+o+"\n\t\tA "+n+" "+n+" 0 "+s+" "+(a?1:0)+"\n\t\t"+l+" "+u}function W(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:1,s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,r=i.x+t.x,o=i.y+t.y,l=i.x+e.x,u=2*n+o,h=i.y+t.y;return"M"+r+" "+o+"\n\t\tA "+n+" "+n+" 0 "+s+" "+(a?1:0)+"\n\t\t"+l+" "+u+"\n\t\tM"+r+" "+u+"\n\t\tA "+n+" "+n+" 0 "+s+" "+(a?1:0)+"\n\t\t"+l+" "+h}function j(t,e){var i=arguments.length>2&&void 0!==arguments[2]&&arguments[2],n="path-fill-gradient-"+e+"-"+(i?"lighter":"default"),a=O(t,n),s=[1,.6,.2];return i&&(s=[.4,.2,0]),M(a,"0%",e,s[0]),M(a,"50%",e,s[1]),M(a,"100%",e,s[2]),n}function F(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:Jt,s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:"none";return L("rect",{className:"percentage-bar",x:t,y:e,width:i,height:n,fill:s,styles:{stroke:A(s,-25),"stroke-dasharray":"0, "+(n+i)+", "+i+", "+n,"stroke-width":a}})}function H(t,e,i,n,a){var s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:"none",r=arguments.length>6&&void 0!==arguments[6]?arguments[6]:{},o={className:t,x:e,y:i,width:n,height:n,rx:a,fill:s};return Object.keys(r).map(function(t){o[t]=r[t]}),L("rect",o)}function I(t,e,i){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"none",a=arguments[4];a=arguments.length>5&&void 0!==arguments[5]&&arguments[5]?b(a,se):a;var s={className:"legend-bar",x:0,y:0,width:i,height:"2px",fill:n},r=L("text",{className:"legend-dataset-text",x:0,y:0,dy:2*re+"px","font-size":1.2*re+"px","text-anchor":"start",fill:le,innerHTML:a}),o=L("g",{transform:"translate("+t+", "+e+")"});return o.appendChild(L("rect",s)),o.appendChild(r),o}function R(t,e,i){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"none",a=arguments[4];a=arguments.length>5&&void 0!==arguments[5]&&arguments[5]?b(a,se):a;var s={className:"legend-dot",cx:0,cy:0,r:i,fill:n},r=L("text",{className:"legend-dataset-text",x:0,y:0,dx:re+"px",dy:re/3+"px","font-size":1.2*re+"px","text-anchor":"start",fill:le,innerHTML:a}),o=L("g",{transform:"translate("+t+", "+e+")"});return o.appendChild(L("circle",s)),o.appendChild(r),o}function Y(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},s=a.fontSize||re;return L("text",{className:t,x:e,y:i,dy:(void 0!==a.dy?a.dy:s/2)+"px","font-size":s+"px",fill:a.fill||le,"text-anchor":a.textAnchor||"start",innerHTML:n})}function B(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};a.stroke||(a.stroke=oe);var s=L("line",{className:"line-vertical "+a.className,x1:0,x2:0,y1:i,y2:n,styles:{stroke:a.stroke}}),r=L("text",{x:0,y:i>n?i+ae:i-ae-re,dy:re+"px","font-size":re+"px","text-anchor":"middle",innerHTML:e+""}),o=L("g",{transform:"translate("+t+", 0)"});return o.appendChild(s),o.appendChild(r),o}function V(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{};a.stroke||(a.stroke=oe),a.lineType||(a.lineType=""),a.shortenNumbers&&(e=x(e));var s=L("line",{className:"line-horizontal "+a.className+("dashed"===a.lineType?"dashed":""),x1:i,x2:n,y1:0,y2:0,styles:{stroke:a.stroke}}),r=L("text",{x:i3&&void 0!==arguments[3]?arguments[3]:{};f(t)||(t=0),n.pos||(n.pos="left"),n.offset||(n.offset=0),n.mode||(n.mode="span"),n.stroke||(n.stroke=oe),n.className||(n.className="");var a=-1*ne,s="span"===n.mode?i+ne:0;return"tick"===n.mode&&"right"===n.pos&&(a=i+ne,s=i),a+=n.offset,s+=n.offset,V(t,e,a,s,{stroke:n.stroke,className:n.className,lineType:n.lineType,shortenNumbers:n.shortenNumbers})}function G(t,e,i){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};f(t)||(t=0),n.pos||(n.pos="bottom"),n.offset||(n.offset=0),n.mode||(n.mode="span"),n.stroke||(n.stroke=oe),n.className||(n.className="");var a=i+ne,s="span"===n.mode?-1*ne:i;return"tick"===n.mode&&"top"===n.pos&&(a=-1*ne,s=0),B(t,e,a,s,{stroke:n.stroke,className:n.className,lineType:n.lineType})}function q(t,e,i){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{};n.labelPos||(n.labelPos="right");var a=L("text",{className:"chart-label",x:"left"===n.labelPos?ae:i-d(e,5)-ae,y:0,dy:re/-2+"px","font-size":re+"px","text-anchor":"start",innerHTML:e+""}),s=V(t,"",0,i,{stroke:n.stroke||oe,className:n.className||"",lineType:n.lineType});return s.appendChild(a),s}function X(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},s=t-e,r=L("rect",{className:"bar mini",styles:{fill:"rgba(228, 234, 239, 0.49)",stroke:oe,"stroke-dasharray":i+", "+s},x:0,y:0,width:i,height:s});a.labelPos||(a.labelPos="right");var o=L("text",{className:"chart-label",x:"left"===a.labelPos?ae:i-d(n+"",4.5)-ae,y:0,dy:re/-2+"px","font-size":re+"px","text-anchor":"start",innerHTML:n+""}),l=L("g",{transform:"translate(0, "+e+")"});return l.appendChild(r),l.appendChild(o),l}function J(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"",s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,r=arguments.length>6&&void 0!==arguments[6]?arguments[6]:0,o=arguments.length>7&&void 0!==arguments[7]?arguments[7]:{},l=m(e,o.zeroLine),u=Vt(l,2),h=u[0],c=u[1];c-=r,0===h&&(h=o.minHeight,c-=o.minHeight),f(t)||(t=0),f(c)||(c=0),f(h,!0)||(h=0),f(i,!0)||(i=0);var d=L("rect",{className:"bar mini",style:"fill: "+n,"data-point-index":s,x:t,y:c,width:i,height:h});if((a+="")||a.length){d.setAttribute("y",0),d.setAttribute("x",0);var p=L("text",{className:"data-point-value",x:i/2,y:0,dy:re/2*-1+"px","font-size":re+"px","text-anchor":"middle",innerHTML:a}),v=L("g",{"data-point-index":s,transform:"translate("+t+", "+c+")"});return v.appendChild(d),v.appendChild(p),v}return d}function K(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:"",s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:0,r=L("circle",{style:"fill: "+n,"data-point-index":s,cx:t,cy:e,r:i});if((a+="")||a.length){r.setAttribute("cy",0),r.setAttribute("cx",0);var o=L("text",{className:"data-point-value",x:0,y:0,dy:re/2*-1-i+"px","font-size":re+"px","text-anchor":"middle",innerHTML:a}),l=L("g",{"data-point-index":s,transform:"translate("+t+", "+e+")"});return l.appendChild(r),l.appendChild(o),l}return r}function $(t,e,i){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:{},s=e.map(function(e,i){return t[i]+","+e}).join("L");n.spline&&(s=k(t,e));var r=S("M"+s,"line-graph-path",i);if(n.heatline){var o=j(a.svgDefs,i);r.style.stroke="url(#"+o+")"}var l={path:r};if(n.regionFill){var u=j(a.svgDefs,i,!0),h="M"+t[0]+","+a.zeroLine+"L"+s+"L"+t.slice(-1)[0]+","+a.zeroLine;l.region=S(h,"region-fill","none","url(#"+u+")")}return l}function Q(t,e,i,n){var a="string"==typeof e?e:e.join(", ");return[t,{transform:i.join(", ")},n,ve,"translate",{transform:a}]}function Z(t,e,i){return Q(t,[i,0],[e,0],pe)}function tt(t,e,i){return Q(t,[0,i],[0,e],pe)}function et(t,e,i,n){var a=e-i,s=t.childNodes[0];return[[s,{height:a,"stroke-dasharray":s.getAttribute("width")+", "+a},pe,ve],Q(t,[0,n],[0,i],pe)]}function it(t,e,i,n){var a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:0,s=m(i,(arguments.length>5&&void 0!==arguments[5]?arguments[5]:{}).zeroLine),r=Vt(s,2),o=r[0],l=r[1];return l-=a,"rect"!==t.nodeName?[[t.childNodes[0],{width:n,height:o},ce,ve],Q(t,t.getAttribute("transform").split("(")[1].slice(0,-1),[e,l],pe)]:[[t,{width:n,height:o,x:e,y:l},ce,ve]]}function nt(t,e,i){return"circle"!==t.nodeName?[Q(t,t.getAttribute("transform").split("(")[1].slice(0,-1),[e,i],pe)]:[[t,{cx:e,cy:i},ce,ve]]}function at(t,e,i,n,a){var s=[],r=i.map(function(t,i){return e[i]+","+t}).join("L");a&&(r=k(e,i));var o=[t.path,{d:"M"+r},de,ve];if(s.push(o),t.region){var l=e[0]+","+n+"L",u="L"+e.slice(-1)[0]+", "+n,h=[t.region,{d:"M"+l+r+u},de,ve];s.push(h)}return s}function st(t,e){return[t,{d:e},ce,ve]}function rt(t,e,i){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"linear",a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:void 0,s=arguments.length>5&&void 0!==arguments[5]?arguments[5]:{},r=t.cloneNode(!0),o=t.cloneNode(!0);for(var l in e){var u=void 0;u="transform"===l?document.createElementNS("http://www.w3.org/2000/svg","animateTransform"):document.createElementNS("http://www.w3.org/2000/svg","animate");var h=s[l]||t.getAttribute(l),c=e[l],d={attributeName:l,from:h,to:c,begin:"0s",dur:i/1e3+"s",values:h+";"+c,keySplines:ge[n],keyTimes:"0;1",calcMode:"spline",fill:"freeze"};a&&(d.type=a);for(var p in d)u.setAttribute(p,d[p]);r.appendChild(u),a?o.setAttribute(l,"translate("+c+")"):o.setAttribute(l,c)}return[r,o]}function ot(t,e){t.style.transform=e,t.style.webkitTransform=e,t.style.msTransform=e,t.style.mozTransform=e,t.style.oTransform=e}function lt(t,e){var i=[],n=[];e.map(function(t){var e=t[0],a=e.parentNode,s=void 0,r=void 0;t[0]=e;var o=rt.apply(void 0,Ut(t)),l=Vt(o,2);s=l[0],r=l[1],i.push(r),n.push([s,a]),a&&a.replaceChild(s,e)});var a=t.cloneNode(!0);return n.map(function(t,n){t[1]&&(t[1].replaceChild(i[n],t[0]),e[n][0]=i[n])}),a}function ut(t,e,i){if(0!==i.length){var n=lt(e,i);e.parentNode==t&&(t.removeChild(e),t.appendChild(n)),setTimeout(function(){n.parentNode==t&&(t.removeChild(n),t.appendChild(e))},fe)}}function ht(t,e){var i=document.createElement("a");i.style="display: none";var n=new Blob(e,{type:"image/svg+xml; charset=utf-8"}),a=window.URL.createObjectURL(n);i.href=a,i.download=t,document.body.appendChild(i),i.click(),setTimeout(function(){document.body.removeChild(i),window.URL.revokeObjectURL(a)},300)}function ct(e){var i=e.cloneNode(!0);i.classList.add("chart-container"),i.setAttribute("xmlns","http://www.w3.org/2000/svg"),i.setAttribute("xmlns:xlink","http://www.w3.org/1999/xlink");var n=t.create("style",{innerHTML:me});i.insertBefore(n,i.firstChild);var a=t.create("div");return a.appendChild(i),a.innerHTML}function dt(t){var e=new Date(t);return e.setMinutes(e.getMinutes()-e.getTimezoneOffset()),e}function pt(t){var e=t.getDate(),i=t.getMonth()+1;return[t.getFullYear(),(i>9?"":"0")+i,(e>9?"":"0")+e].join("-")}function ft(t){return new Date(t.getTime())}function vt(t,e){var i=xt(t);return Math.ceil(gt(i,e)/xe)}function gt(t,e){var i=we*ke;return(dt(e)-dt(t))/i}function mt(t,e){return t.getMonth()===e.getMonth()&&t.getFullYear()===e.getFullYear()}function yt(t){var e=arguments.length>1&&void 0!==arguments[1]&&arguments[1],i=Ae[t];return e?i.slice(0,3):i}function bt(t,e){return new Date(e,t+1,0)}function xt(t){var e=ft(t),i=e.getDay();return 0!==i&&kt(e,-1*i),e}function kt(t,e){t.setDate(t.getDate()+e)}function wt(t,e,i){var n=Object.keys(Le).filter(function(e){return t.includes(e)}),a=Le[n[0]];return Object.assign(a,{constants:e,getData:i}),new Te(a)}function At(t){if(0===t)return[0,0];if(isNaN(t))return{mantissa:-6755399441055744,exponent:972};var e=t>0?1:-1;if(!isFinite(t))return{mantissa:4503599627370496*e,exponent:972};t=Math.abs(t);var i=Math.floor(Math.log10(t));return[e*(t/Math.pow(10,i)),i]}function Pt(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=Math.ceil(t),n=Math.floor(e),a=i-n,s=a,r=1;a>5&&(a%2!=0&&(a=++i-n),s=a/2,r=2),a<=2&&(r=a/(s=4)),0===a&&(s=5,r=1);for(var o=[],l=0;l<=s;l++)o.push(n+r*l);return o}function Tt(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,i=At(t),n=Vt(i,2),a=n[0],s=n[1],r=e?e/Math.pow(10,s):0,o=Pt(a=a.toFixed(6),r);return o=o.map(function(t){return t*Math.pow(10,s)})}function Lt(t){function e(t,e){for(var i=Tt(t),n=i[1]-i[0],a=0,s=1;a1&&void 0!==arguments[1]&&arguments[1],n=Math.max.apply(Math,Ut(t)),a=Math.min.apply(Math,Ut(t)),s=[];if(n>=0&&a>=0)At(n)[1],s=i?Tt(n,a):Tt(n);else if(n>0&&a<0){var r=Math.abs(a);n>=r?(At(n)[1],s=e(n,r)):(At(r)[1],s=e(r,n).reverse().map(function(t){return-1*t}))}else if(n<=0&&a<=0){var o=Math.abs(a),l=Math.abs(n);At(o)[1],s=(s=i?Tt(o,l):Tt(o)).reverse().map(function(t){return-1*t})}return s}function Ot(t){var e=Mt(t);return t.indexOf(0)>=0?t.indexOf(0):t[0]>0?-1*t[0]/e:-1*t[t.length-1]/e+(t.length-1)}function Mt(t){return t[1]-t[0]}function Ct(t){return t[t.length-1]-t[0]}function Dt(t,e){return h(e.zeroLine-t*e.scaleMultiplier)}function Nt(t,e){var i=arguments.length>2&&void 0!==arguments[2]&&arguments[2],n=e.reduce(function(e,i){return Math.abs(i-t)i?n.slice(0,i):c(n,i-n.length,0),t.values=n}else t.values=a;t.chartType||(Xt.includes(e),t.chartType=e)}),t.yRegions&&t.yRegions.map(function(t){if(t.end1&&void 0!==arguments[1]?arguments[1]:[],i=!(arguments.length>2&&void 0!==arguments[2])||arguments[2],n=t/e.length;n<=0&&(n=1);var a=n/Kt,s=void 0;if(i){var r=Math.max.apply(Math,Ut(e.map(function(t){return t.length})));s=Math.ceil(r/a)}return e.map(function(t,e){return(t+="").length>a&&(i?e%s!=0&&(t=""):t=a-3>0?t.slice(0,a-3)+" ...":t.slice(0,a)+".."),t})}function jt(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"line",e=arguments[1],i=arguments[2];return"axis-mixed"===t?(i.type="line",new De(e,i)):Se[t]?new Se[t](e,i):void console.error("Undefined chart type: "+t)}!function(t,e){void 0===e&&(e={});var i=e.insertAt;if(t&&"undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],a=document.createElement("style");a.type="text/css","top"===i&&n.firstChild?n.insertBefore(a,n.firstChild):n.appendChild(a),a.styleSheet?a.styleSheet.cssText=t:a.appendChild(document.createTextNode(t))}}('.chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ol,.graph-svg-tip ul{padding-left:0;display:-webkit-box;display:-ms-flexbox;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;-webkit-box-flex:1;-ms-flex:1;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:" ";border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}');var Ft="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Ht=(function(){function t(t){this.value=t}function e(e){function i(t,e){return new Promise(function(i,a){var o={key:t,arg:e,resolve:i,reject:a,next:null};r?r=r.next=o:(s=r=o,n(t,e))})}function n(i,s){try{var r=e[i](s),o=r.value;o instanceof t?Promise.resolve(o.value).then(function(t){n("next",t)},function(t){n("throw",t)}):a(r.done?"return":"normal",r.value)}catch(t){a("throw",t)}}function a(t,e){switch(t){case"return":s.resolve({value:e,done:!0});break;case"throw":s.reject(e);break;default:s.resolve({value:e,done:!1})}(s=s.next)?n(s.key,s.arg):r=null}var s,r;this._invoke=i,"function"!=typeof e.return&&(this.return=void 0)}"function"==typeof Symbol&&Symbol.asyncIterator&&(e.prototype[Symbol.asyncIterator]=function(){return this}),e.prototype.next=function(t){return this._invoke("next",t)},e.prototype.throw=function(t){return this._invoke("throw",t)},e.prototype.return=function(t){return this._invoke("return",t)}}(),function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}),It=function(){function t(t,e){for(var i=0;i\n\t\t\t\t
              \n\t\t\t\t
              '}),this.hideTip(),this.title=this.container.querySelector(".title"),this.dataPointList=this.container.querySelector(".data-point-list"),this.parent.addEventListener("mouseleave",function(){e.hideTip()})}},{key:"fill",value:function(){var e=this,i=void 0;this.index&&this.container.setAttribute("data-point-index",this.index),i=this.titleValueFirst?""+this.titleValue+""+this.titleName:this.titleName+""+this.titleValue+"",this.title.innerHTML=i,this.dataPointList.innerHTML="",this.listValues.map(function(i,n){var a=e.colors[n]||"black",s=0===i.formatted||i.formatted?i.formatted:i.value,r=t.create("li",{styles:{"border-top":"3px solid "+a},innerHTML:''+(0===s||s?s:"")+"\n\t\t\t\t\t"+(i.title?i.title:"")});e.dataPointList.appendChild(r)})}},{key:"calcPosition",value:function(){var t=this.container.offsetWidth;this.top=this.y-this.container.offsetHeight-5,this.left=this.x-t/2;var e=this.parent.offsetWidth-t,i=this.container.querySelector(".svg-pointer");if(this.left<0)i.style.left="calc(50% - "+-1*this.left+"px)",this.left=0;else if(this.left>e){var n="calc(50% + "+(this.left-e)+"px)";i.style.left=n,this.left=e}else i.style.left="50%"}},{key:"setValues",value:function(t,e){var i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:[],a=arguments.length>4&&void 0!==arguments[4]?arguments[4]:-1;this.titleName=i.name,this.titleValue=i.value,this.listValues=n,this.x=t,this.y=e,this.titleValueFirst=i.valueFirst||0,this.index=a,this.refresh()}},{key:"hideTip",value:function(){this.container.style.top="0px",this.container.style.left="0px",this.container.style.opacity="0"}},{key:"showTip",value:function(){this.container.style.top=this.top+"px",this.container.style.left=this.left+"px",this.container.style.opacity="1"}}]),e}(),ee={"light-blue":"#7cd6fd",blue:"#5e64ff",violet:"#743ee2",red:"#ff5858",orange:"#ffa00a",yellow:"#feef72",green:"#28a745","light-green":"#98d85b",purple:"#b554ff",magenta:"#ffa3ef",black:"#36114C",grey:"#bdd3e6","light-grey":"#f0f4f7","dark-grey":"#b8c2cc"},ie=function(t){return/rgb[a]{0,1}\([\d, ]+\)/gim.test(t)?/\D+(\d*)\D+(\d*)\D+(\d*)/gim.exec(t).map(function(t,e){return 0!==e?Number(t).toString(16):"#"}).reduce(function(t,e){return""+t+e}):ee[t]||t},ne=6,ae=4,se=15,re=10,oe="#dadada",le="#555b51",ue={bar:function(t){var e=void 0;"rect"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);var i=t.cloneNode();return i.style.fill="#000000",i.style.opacity="0.4",e&&i.setAttribute("transform",e),i},dot:function(t){var e=void 0;"circle"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);var i=t.cloneNode(),n=t.getAttribute("r"),a=t.getAttribute("fill");return i.setAttribute("r",parseInt(n)+4),i.setAttribute("fill",a),i.style.opacity="0.6",e&&i.setAttribute("transform",e),i},heat_square:function(t){var e=void 0;"circle"!==t.nodeName&&(e=t.getAttribute("transform"),t=t.childNodes[0]);var i=t.cloneNode(),n=t.getAttribute("r"),a=t.getAttribute("fill");return i.setAttribute("r",parseInt(n)+4),i.setAttribute("fill",a),i.style.opacity="0.6",e&&i.setAttribute("transform",e),i}},he={bar:function(t,e){var i=void 0;"rect"!==t.nodeName&&(i=t.getAttribute("transform"),t=t.childNodes[0]);var n=["x","y","width","height"];Object.values(t.attributes).filter(function(t){return n.includes(t.name)&&t.specified}).map(function(t){e.setAttribute(t.name,t.nodeValue)}),i&&e.setAttribute("transform",i)},dot:function(t,e){var i=void 0;"circle"!==t.nodeName&&(i=t.getAttribute("transform"),t=t.childNodes[0]);var n=["cx","cy"];Object.values(t.attributes).filter(function(t){return n.includes(t.name)&&t.specified}).map(function(t){e.setAttribute(t.name,t.nodeValue)}),i&&e.setAttribute("transform",i)},heat_square:function(t,e){var i=void 0;"circle"!==t.nodeName&&(i=t.getAttribute("transform"),t=t.childNodes[0]);var n=["cx","cy"];Object.values(t.attributes).filter(function(t){return n.includes(t.name)&&t.specified}).map(function(t){e.setAttribute(t.name,t.nodeValue)}),i&&e.setAttribute("transform",i)}},ce=350,de=350,pe=ce,fe=250,ve="easein",ge={ease:"0.25 0.1 0.25 1",linear:"0 0 1 1",easein:"0.1 0.8 0.2 1",easeout:"0 0 0.58 1",easeinout:"0.42 0 0.58 1"},me=".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}",ye=function(){function e(t,i){if(Ht(this,e),i=g(i),this.parent="string"==typeof t?document.querySelector(t):t,!(this.parent instanceof HTMLElement))throw new Error("No `parent` element to render on was provided.");this.rawChartArgs=i,this.title=i.title||"",this.type=i.type||"",this.realData=this.prepareData(i.data),this.data=this.prepareFirstData(this.realData),this.colors=this.validateColors(i.colors,this.type),this.config={showTooltip:1,showLegend:1,isNavigable:i.isNavigable||0,animate:void 0!==i.animate?i.animate:1,truncateLegends:i.truncateLegends||1},this.measures=JSON.parse(JSON.stringify(Gt));var n=this.measures;this.setMeasures(i),this.title.length||(n.titleHeight=0),this.config.showLegend||(n.legendHeight=0),this.argHeight=i.height||n.baseHeight,this.state={},this.options={},this.initTimeout=qt,this.config.isNavigable&&(this.overlays=[]),this.configure(i)}return It(e,[{key:"prepareData",value:function(t){return t}},{key:"prepareFirstData",value:function(t){return t}},{key:"validateColors",value:function(t,e){var i=[];return(t=(t||[]).concat(Qt[e])).forEach(function(t){var e=ie(t);P(e)?i.push(e):console.warn('"'+t+'" is not a valid color.')}),i}},{key:"setMeasures",value:function(){}},{key:"configure",value:function(){var t=this,e=this.argHeight;this.baseHeight=e,this.height=e-l(this.measures),this.boundDrawFn=function(){return t.draw(!0)},ResizeObserver&&(this.resizeObserver=new ResizeObserver(this.boundDrawFn),this.resizeObserver.observe(this.parent)),window.addEventListener("resize",this.boundDrawFn),window.addEventListener("orientationchange",this.boundDrawFn)}},{key:"destroy",value:function(){this.resizeObserver&&this.resizeObserver.disconnect(),window.removeEventListener("resize",this.boundDrawFn),window.removeEventListener("orientationchange",this.boundDrawFn)}},{key:"setup",value:function(){this.makeContainer(),this.updateWidth(),this.makeTooltip(),this.draw(!1,!0)}},{key:"makeContainer",value:function(){this.parent.innerHTML="";var e={inside:this.parent,className:"chart-container"};this.independentWidth&&(e.styles={width:this.independentWidth+"px"}),this.container=t.create("div",e)}},{key:"makeTooltip",value:function(){this.tip=new te({parent:this.container,colors:this.colors}),this.bindTooltip()}},{key:"bindTooltip",value:function(){}},{key:"draw",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],n=arguments.length>1&&void 0!==arguments[1]&&arguments[1];e&&i(this.parent)||(this.updateWidth(),this.calc(e),this.makeChartArea(),this.setupComponents(),this.components.forEach(function(e){return e.setup(t.drawArea)}),this.render(this.components,!1),n&&(this.data=this.realData,setTimeout(function(){t.update(t.data)},this.initTimeout)),this.renderLegend(),this.setupNavigation(n))}},{key:"calc",value:function(){}},{key:"updateWidth",value:function(){this.baseWidth=a(this.parent),this.width=this.baseWidth-u(this.measures)}},{key:"makeChartArea",value:function(){this.svg&&this.container.removeChild(this.svg);var t=this.measures;this.svg=C(this.container,"frappe-chart chart",this.baseWidth,this.baseHeight),this.svgDefs=D(this.svg),this.title.length&&(this.titleEL=Y("title",t.margins.left,t.margins.top,this.title,{fontSize:t.titleFontSize,fill:"#666666",dy:t.titleFontSize}));var e=r(t);this.drawArea=N(this.type+"-chart chart-draw-area","translate("+o(t)+", "+e+")"),this.config.showLegend&&(e+=this.height+t.paddings.bottom,this.legendArea=N("chart-legend","translate("+o(t)+", "+e+")")),this.title.length&&this.svg.appendChild(this.titleEL),this.svg.appendChild(this.drawArea),this.config.showLegend&&this.svg.appendChild(this.legendArea),this.updateTipOffset(o(t),r(t))}},{key:"updateTipOffset",value:function(t,e){this.tip.offset={x:t,y:e}}},{key:"setupComponents",value:function(){this.components=new Map}},{key:"update",value:function(t){t||console.error("No data to update."),this.data=this.prepareData(t),this.calc(),this.render(this.components,this.config.animate),this.renderLegend()}},{key:"render",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.components,i=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];this.config.isNavigable&&this.overlays.map(function(t){return t.parentNode.removeChild(t)});var n=[];e.forEach(function(t){n=n.concat(t.update(i))}),n.length>0?(ut(this.container,this.svg,n),setTimeout(function(){e.forEach(function(t){return t.make()}),t.updateNav()},400)):(e.forEach(function(t){return t.make()}),this.updateNav())}},{key:"updateNav",value:function(){this.config.isNavigable&&(this.makeOverlay(),this.bindUnits())}},{key:"renderLegend",value:function(){}},{key:"setupNavigation",value:function(){var t=this,e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.config.isNavigable&&e&&(this.bindOverlay(),this.keyActions={13:this.onEnterKey.bind(this),37:this.onLeftArrow.bind(this),38:this.onUpArrow.bind(this),39:this.onRightArrow.bind(this),40:this.onDownArrow.bind(this)},document.addEventListener("keydown",function(e){n(t.container)&&(e=e||window.event,t.keyActions[e.keyCode]&&t.keyActions[e.keyCode]())}))}},{key:"makeOverlay",value:function(){}},{key:"updateOverlay",value:function(){}},{key:"bindOverlay",value:function(){}},{key:"bindUnits",value:function(){}},{key:"onLeftArrow",value:function(){}},{key:"onRightArrow",value:function(){}},{key:"onUpArrow",value:function(){}},{key:"onDownArrow",value:function(){}},{key:"onEnterKey",value:function(){}},{key:"addDataPoint",value:function(){}},{key:"removeDataPoint",value:function(){}},{key:"getDataPoint",value:function(){}},{key:"setCurrentDataPoint",value:function(){}},{key:"updateDataset",value:function(){}},{key:"export",value:function(){var t=ct(this.svg);ht(this.title||"Chart",[t])}}]),e}(),be=function(t){function e(t,i){return Ht(this,e),Bt(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t,i))}return Yt(e,t),It(e,[{key:"configure",value:function(t){Rt(e.prototype.__proto__||Object.getPrototypeOf(e.prototype),"configure",this).call(this,t),this.config.formatTooltipY=(t.tooltipOptions||{}).formatTooltipY,this.config.maxSlices=t.maxSlices||20,this.config.maxLegendPoints=t.maxLegendPoints||20}},{key:"calc",value:function(){var t=this,e=this.state,i=this.config.maxSlices;e.sliceTotals=[];var n=this.data.labels.map(function(e,i){var n=0;return t.data.datasets.map(function(t){n+=t.values[i]}),[n,e]}).filter(function(t){return t[0]>=0}),a=n;if(n.length>i){n.sort(function(t,e){return e[0]-t[0]}),a=n.slice(0,i-1);var s=0;n.slice(i-1).map(function(t){s+=t[0]}),a.push([s,"Rest"]),this.colors[i-1]="grey"}e.labels=[],a.map(function(t){e.sliceTotals.push(v(t[0])),e.labels.push(t[1])}),e.grandTotal=e.sliceTotals.reduce(function(t,e){return t+e},0),this.center={x:this.width/2,y:this.height/2}}},{key:"renderLegend",value:function(){var t=this,e=this.state;this.legendArea.textContent="",this.legendTotals=e.sliceTotals.slice(0,this.config.maxLegendPoints);var i=0,n=0;this.legendTotals.map(function(a,s){var r=150,o=Math.floor((t.width-u(t.measures))/r);t.legendTotals.lengtho&&(i=0,n+=20);var l=r*i+5,h=t.config.truncateLegends?b(e.labels[s],r/10):e.labels[s],c=t.config.formatTooltipY?t.config.formatTooltipY(a):a,d=R(l,n,5,t.colors[s],h+": "+c,!1);t.legendArea.appendChild(d),i++})}}]),e}(ye),xe=7,ke=1e3,we=86400,Ae=["January","February","March","April","May","June","July","August","September","October","November","December"],Pe=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],Te=function(){function t(e){var i=e.layerClass,n=void 0===i?"":i,a=e.layerTransform,s=void 0===a?"":a,r=e.constants,o=e.getData,l=e.makeElements,u=e.animateElements;Ht(this,t),this.layerTransform=s,this.constants=r,this.makeElements=l,this.getData=o,this.animateElements=u,this.store=[],this.labels=[],this.layerClass=n,this.layerClass="function"==typeof this.layerClass?this.layerClass():this.layerClass,this.refresh()}return It(t,[{key:"refresh",value:function(t){this.data=t||this.getData()}},{key:"setup",value:function(t){this.layer=N(this.layerClass,this.layerTransform,t)}},{key:"make",value:function(){this.render(this.data),this.oldData=this.data}},{key:"render",value:function(t){var e=this;this.store=this.makeElements(t),this.layer.textContent="",this.store.forEach(function(t){e.layer.appendChild(t)}),this.labels.forEach(function(t){e.layer.appendChild(t)})}},{key:"update",value:function(){var t=!(arguments.length>0&&void 0!==arguments[0])||arguments[0];this.refresh();var e=[];return t&&(e=this.animateElements(this.data)||[]),e}}]),t}(),Le={donutSlices:{layerClass:"donut-slices",makeElements:function(t){return t.sliceStrings.map(function(e,i){var n=S(e,"donut-path",t.colors[i],"none",t.strokeWidth);return n.style.transition="transform .3s;",n})},animateElements:function(t){return this.store.map(function(e,i){return st(e,t.sliceStrings[i])})}},pieSlices:{layerClass:"pie-slices",makeElements:function(t){return t.sliceStrings.map(function(e,i){var n=S(e,"pie-path","none",t.colors[i]);return n.style.transition="transform .3s;",n})},animateElements:function(t){return this.store.map(function(e,i){return st(e,t.sliceStrings[i])})}},percentageBars:{layerClass:"percentage-bars",makeElements:function(t){var e=this;return t.xPositions.map(function(i,n){return F(i,0,t.widths[n],e.constants.barHeight,e.constants.barDepth,t.colors[n])})},animateElements:function(t){if(t)return[]}},yAxis:{layerClass:"y axis",makeElements:function(t){var e=this;return t.positions.map(function(i,n){return U(i,t.labels[n],e.constants.width,{mode:e.constants.mode,pos:e.constants.pos,shortenNumbers:e.constants.shortenNumbers})})},animateElements:function(t){var e=t.positions,i=t.labels,n=this.oldData.positions,a=this.oldData.labels,s=y(n,e),r=Vt(s,2);n=r[0],e=r[1];var o=y(a,i),l=Vt(o,2);return a=l[0],i=l[1],this.render({positions:n,labels:i}),this.store.map(function(t,i){return tt(t,e[i],n[i])})}},xAxis:{layerClass:"x axis",makeElements:function(t){var e=this;return t.positions.map(function(i,n){return G(i,t.calcLabels[n],e.constants.height,{mode:e.constants.mode,pos:e.constants.pos})})},animateElements:function(t){var e=t.positions,i=t.calcLabels,n=this.oldData.positions,a=this.oldData.calcLabels,s=y(n,e),r=Vt(s,2);n=r[0],e=r[1];var o=y(a,i),l=Vt(o,2);return a=l[0],i=l[1],this.render({positions:n,calcLabels:i}),this.store.map(function(t,i){return Z(t,e[i],n[i])})}},yMarkers:{layerClass:"y-markers",makeElements:function(t){var e=this;return t.map(function(t){return q(t.position,t.label,e.constants.width,{labelPos:t.options.labelPos,mode:"span",lineType:"dashed"})})},animateElements:function(t){var e=y(this.oldData,t),i=Vt(e,2);this.oldData=i[0];var n=(t=i[1]).map(function(t){return t.position}),a=t.map(function(t){return t.label}),s=t.map(function(t){return t.options}),r=this.oldData.map(function(t){return t.position});return this.render(r.map(function(t,e){return{position:r[e],label:a[e],options:s[e]}})),this.store.map(function(t,e){return tt(t,n[e],r[e])})}},yRegions:{layerClass:"y-regions",makeElements:function(t){var e=this;return t.map(function(t){return X(t.startPos,t.endPos,e.constants.width,t.label,{labelPos:t.options.labelPos})})},animateElements:function(t){var e=y(this.oldData,t),i=Vt(e,2);this.oldData=i[0];var n=(t=i[1]).map(function(t){return t.endPos}),a=t.map(function(t){return t.label}),s=t.map(function(t){return t.startPos}),r=t.map(function(t){return t.options}),o=this.oldData.map(function(t){return t.endPos}),l=this.oldData.map(function(t){return t.startPos});this.render(o.map(function(t,e){return{startPos:l[e],endPos:o[e],label:a[e],options:r[e]}}));var u=[];return this.store.map(function(t,e){u=u.concat(et(t,s[e],n[e],o[e]))}),u}},heatDomain:{layerClass:function(){return"heat-domain domain-"+this.constants.index},makeElements:function(t){var e=this,i=this.constants,n=i.index,a=i.colWidth,s=i.rowHeight,r=i.squareSize,o=i.radius,l=i.xTranslate,u=0;return this.serializedSubDomains=[],t.cols.map(function(t,i){1===i&&e.labels.push(Y("domain-name",l,-12,yt(n,!0).toUpperCase(),{fontSize:9})),t.map(function(t,i){if(t.fill){var n={"data-date":t.yyyyMmDd,"data-value":t.dataValue,"data-day":i},a=H("day",l,u,r,o,t.fill,n);e.serializedSubDomains.push(a)}u+=s}),u=0,l+=a}),this.serializedSubDomains},animateElements:function(t){if(t)return[]}},barGraph:{layerClass:function(){return"dataset-units dataset-bars dataset-"+this.constants.index},makeElements:function(t){var e=this.constants;return this.unitType="bar",this.units=t.yPositions.map(function(i,n){return J(t.xPositions[n],i,t.barWidth,e.color,t.labels[n],n,t.offsets[n],{zeroLine:t.zeroLine,barsWidth:t.barsWidth,minHeight:e.minHeight})}),this.units},animateElements:function(t){var e=t.xPositions,i=t.yPositions,n=t.offsets,a=t.labels,s=this.oldData.xPositions,r=this.oldData.yPositions,o=this.oldData.offsets,l=this.oldData.labels,u=y(s,e),h=Vt(u,2);s=h[0],e=h[1];var c=y(r,i),d=Vt(c,2);r=d[0],i=d[1];var p=y(o,n),f=Vt(p,2);o=f[0],n=f[1];var v=y(l,a),g=Vt(v,2);l=g[0],a=g[1],this.render({xPositions:s,yPositions:r,offsets:o,labels:a,zeroLine:this.oldData.zeroLine,barsWidth:this.oldData.barsWidth,barWidth:this.oldData.barWidth});var m=[];return this.store.map(function(a,s){m=m.concat(it(a,e[s],i[s],t.barWidth,n[s],{zeroLine:t.zeroLine}))}),m}},lineGraph:{layerClass:function(){return"dataset-units dataset-line dataset-"+this.constants.index},makeElements:function(t){var e=this.constants;return this.unitType="dot",this.paths={},e.hideLine||(this.paths=$(t.xPositions,t.yPositions,e.color,{heatline:e.heatline,regionFill:e.regionFill,spline:e.spline},{svgDefs:e.svgDefs,zeroLine:t.zeroLine})),this.units=[],e.hideDots||(this.units=t.yPositions.map(function(i,n){return K(t.xPositions[n],i,t.radius,e.color,e.valuesOverPoints?t.values[n]:"",n)})),Object.values(this.paths).concat(this.units)},animateElements:function(t){var e=t.xPositions,i=t.yPositions,n=t.values,a=this.oldData.xPositions,s=this.oldData.yPositions,r=this.oldData.values,o=y(a,e),l=Vt(o,2);a=l[0],e=l[1];var u=y(s,i),h=Vt(u,2);s=h[0],i=h[1];var c=y(r,n),d=Vt(c,2);r=d[0],n=d[1],this.render({xPositions:a,yPositions:s,values:n,zeroLine:this.oldData.zeroLine,radius:this.oldData.radius});var p=[];return Object.keys(this.paths).length&&(p=p.concat(at(this.paths,e,i,t.zeroLine,this.constants.spline))),this.units.length&&this.units.map(function(t,n){p=p.concat(nt(t,e[n],i[n]))}),p}}},Oe=function(t){function i(t,e){Ht(this,i);var n=Bt(this,(i.__proto__||Object.getPrototypeOf(i)).call(this,t,e));return n.type="percentage",n.setup(),n}return Yt(i,t),It(i,[{key:"setMeasures",value:function(t){var e=this.measures;this.barOptions=t.barOptions||{};var i=this.barOptions;i.height=i.height||20,i.depth=i.depth||Jt,e.paddings.right=30,e.legendHeight=60,e.baseHeight=8*(i.height+.5*i.depth)}},{key:"setupComponents",value:function(){var t=this.state,e=[["percentageBars",{barHeight:this.barOptions.height,barDepth:this.barOptions.depth},function(){return{xPositions:t.xPositions,widths:t.widths,colors:this.colors}}.bind(this)]];this.components=new Map(e.map(function(t){var e=wt.apply(void 0,Ut(t));return[t[0],e]}))}},{key:"calc",value:function(){var t=this;Rt(i.prototype.__proto__||Object.getPrototypeOf(i.prototype),"calc",this).call(this);var e=this.state;e.xPositions=[],e.widths=[];var n=0;e.sliceTotals.map(function(i){var a=t.width*i/e.grandTotal;e.widths.push(a),e.xPositions.push(n),n+=a})}},{key:"makeDataByIndex",value:function(){}},{key:"bindTooltip",value:function(){var t=this,i=this.state;this.container.addEventListener("mousemove",function(n){var a=t.components.get("percentageBars").store,s=n.target;if(a.includes(s)){var r=a.indexOf(s),o=e(t.container),l=e(s),u=l.left-o.left+parseInt(s.getAttribute("width"))/2,h=l.top-o.top,c=(t.formattedLabels&&t.formattedLabels.length>0?t.formattedLabels[r]:t.state.labels[r])+": ",d=i.sliceTotals[r]/i.grandTotal;t.tip.setValues(u,h,{name:c,value:(100*d).toFixed(1)+"%"}),t.tip.showTip()}})}}]),i}(be),Me=function(t){function i(t,e){Ht(this,i);var n=Bt(this,(i.__proto__||Object.getPrototypeOf(i)).call(this,t,e));return n.type="pie",n.initTimeout=0,n.init=1,n.setup(),n}return Yt(i,t),It(i,[{key:"configure",value:function(t){Rt(i.prototype.__proto__||Object.getPrototypeOf(i.prototype),"configure",this).call(this,t),this.mouseMove=this.mouseMove.bind(this),this.mouseLeave=this.mouseLeave.bind(this),this.hoverRadio=t.hoverRadio||.1,this.config.startAngle=t.startAngle||0,this.clockWise=t.clockWise||!1}},{key:"calc",value:function(){var t=this;Rt(i.prototype.__proto__||Object.getPrototypeOf(i.prototype),"calc",this).call(this);var e=this.state;this.radius=this.height>this.width?this.center.x:this.center.y;var n=this.radius,a=this.clockWise,s=e.slicesProperties||[];e.sliceStrings=[],e.slicesProperties=[];var r=180-this.config.startAngle;e.sliceTotals.map(function(i,o){var l=r,u=i/e.grandTotal*360,h=u>180?1:0,c=a?-u:u,d=r+=c,f=p(l,n),v=p(d,n),g=t.init&&s[o],m=void 0,y=void 0;t.init?(m=g?g.startPosition:f,y=g?g.endPosition:f):(m=f,y=v);var b=360===u?_(m,y,t.center,t.radius,a,h):E(m,y,t.center,t.radius,a,h);e.sliceStrings.push(b),e.slicesProperties.push({startPosition:f,endPosition:v,value:i,total:e.grandTotal,startAngle:l,endAngle:d,angle:c})}),this.init=0}},{key:"setupComponents",value:function(){var t=this.state,e=[["pieSlices",{},function(){return{sliceStrings:t.sliceStrings,colors:this.colors}}.bind(this)]];this.components=new Map(e.map(function(t){var e=wt.apply(void 0,Ut(t));return[t[0],e]}))}},{key:"calTranslateByAngle",value:function(t){var e=this.radius,i=this.hoverRadio,n=p(t.startAngle+t.angle/2,e);return"translate3d("+n.x*i+"px,"+n.y*i+"px,0)"}},{key:"hoverSlice",value:function(t,i,n,a){if(t){var s=this.colors[i];if(n){ot(t,this.calTranslateByAngle(this.state.slicesProperties[i])),t.style.fill=A(s,50);var r=e(this.svg),o=a.pageX-r.left+10,l=a.pageY-r.top-10,u=(this.formatted_labels&&this.formatted_labels.length>0?this.formatted_labels[i]:this.state.labels[i])+": ",h=(100*this.state.sliceTotals[i]/this.state.grandTotal).toFixed(1);this.tip.setValues(o,l,{name:u,value:h+"%"}),this.tip.showTip()}else ot(t,"translate3d(0,0,0)"),this.tip.hideTip(),t.style.fill=s}}},{key:"bindTooltip",value:function(){this.container.addEventListener("mousemove",this.mouseMove),this.container.addEventListener("mouseleave",this.mouseLeave)}},{key:"mouseMove",value:function(t){var e=t.target,i=this.components.get("pieSlices").store,n=this.curActiveSliceIndex,a=this.curActiveSlice;if(i.includes(e)){var s=i.indexOf(e);this.hoverSlice(a,n,!1),this.curActiveSlice=e,this.curActiveSliceIndex=s,this.hoverSlice(e,s,!0,t)}else this.mouseLeave()}},{key:"mouseLeave",value:function(){this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,!1)}}]),i}(be),Ce=function(t){function e(t,i){Ht(this,e);var n=Bt(this,(e.__proto__||Object.getPrototypeOf(e)).call(this,t,i));n.type="heatmap",n.countLabel=i.countLabel||"";var a=["Sunday","Monday"],s=a.includes(i.startSubDomain)?i.startSubDomain:"Sunday";return n.startSubDomainIndex=a.indexOf(s),n.setup(),n}return Yt(e,t),It(e,[{key:"setMeasures",value:function(t){var e=this.measures;this.discreteDomains=0===t.discreteDomains?0:1,e.paddings.top=36,e.paddings.bottom=0,e.legendHeight=24,e.baseHeight=12*xe+l(e);var i=this.data,n=this.discreteDomains?12:0;this.independentWidth=12*(vt(i.start,i.end)+n)+u(e)}},{key:"updateWidth",value:function(){var t=this.discreteDomains?12:0,e=this.state.noOfWeeks?this.state.noOfWeeks:52;this.baseWidth=12*(e+t)+u(this.measures)}},{key:"prepareData",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.data;if(t.start&&t.end&&t.start>t.end)throw new Error("Start date cannot be greater than end date.");if(t.start||(t.start=new Date,t.start.setFullYear(t.start.getFullYear()-1)),t.end||(t.end=new Date),t.dataPoints=t.dataPoints||{},parseInt(Object.keys(t.dataPoints)[0])>1e5){var e={};Object.keys(t.dataPoints).forEach(function(i){var n=new Date(i*ke);e[pt(n)]=t.dataPoints[i]}),t.dataPoints=e}return t}},{key:"calc",value:function(){var t=this.state;t.start=ft(this.data.start),t.end=ft(this.data.end),t.firstWeekStart=ft(t.start),t.noOfWeeks=vt(t.start,t.end),t.distribution=St(Object.values(this.data.dataPoints),5),t.domainConfigs=this.getDomains()}},{key:"setupComponents",value:function(){var t=this,e=this.state,i=this.discreteDomains?0:1,n=e.domainConfigs.map(function(n,a){return["heatDomain",{index:n.index,colWidth:12,rowHeight:12,squareSize:10,radius:t.rawChartArgs.radius||0,xTranslate:12*e.domainConfigs.filter(function(t,e){return e1&&void 0!==arguments[1]?arguments[1]:"",i=[t.getMonth(),t.getFullYear()],n=i[0],a=i[1],s=xt(t),r={index:n,cols:[]};kt(e=ft(e)||bt(n,a),1);for(var o=vt(s,e),l=[],u=void 0,h=0;h2&&void 0!==arguments[2]&&arguments[2],n=this.state,a=ft(t),s=[],r=0;r=n.start&&a<=n.end;i||a.getMonth()!==e||!l?o.yyyyMmDd=pt(a):o=this.getSubDomainConfig(a),s.push(o)}return s}},{key:"getSubDomainConfig",value:function(t){var e=pt(t),i=this.data.dataPoints[e];return{yyyyMmDd:e,dataValue:i||0,fill:this.colors[Et(i,this.state.distribution)]}}}]),e}(ye),De=function(t){function i(t,e){Ht(this,i);var n=Bt(this,(i.__proto__||Object.getPrototypeOf(i)).call(this,t,e));return n.barOptions=e.barOptions||{},n.lineOptions=e.lineOptions||{},n.type=e.type||"line",n.init=1,n.setup(),n}return Yt(i,t),It(i,[{key:"setMeasures",value:function(){this.data.datasets.length<=1&&(this.config.showLegend=0,this.measures.paddings.bottom=30)}},{key:"configure",value:function(t){Rt(i.prototype.__proto__||Object.getPrototypeOf(i.prototype),"configure",this).call(this,t),t.axisOptions=t.axisOptions||{},t.tooltipOptions=t.tooltipOptions||{},this.config.xAxisMode=t.axisOptions.xAxisMode||"span",this.config.yAxisMode=t.axisOptions.yAxisMode||"span",this.config.xIsSeries=t.axisOptions.xIsSeries||0,this.config.shortenYAxisNumbers=t.axisOptions.shortenYAxisNumbers||0,this.config.formatTooltipX=t.tooltipOptions.formatTooltipX,this.config.formatTooltipY=t.tooltipOptions.formatTooltipY,this.config.valuesOverPoints=t.valuesOverPoints}},{key:"prepareData",value:function(){return _t(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.data,this.type)}},{key:"prepareFirstData",value:function(){return zt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.data)}},{key:"calc",value:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];this.calcXPositions(),t||this.calcYAxisParameters(this.getAllYValues(),"line"===this.type),this.makeDataByIndex()}},{key:"calcXPositions",value:function(){var t=this.state,e=this.data.labels;t.datasetLength=e.length,t.unitWidth=this.width/t.datasetLength,t.xOffset=t.unitWidth/2,t.xAxis={labels:e,positions:e.map(function(e,i){return h(t.xOffset+i*t.unitWidth)})}}},{key:"calcYAxisParameters",value:function(t){var e=Lt(t,arguments.length>1&&void 0!==arguments[1]?arguments[1]:"false"),i=this.height/Ct(e),n=Mt(e)*i,a=this.height-Ot(e)*n;this.state.yAxis={labels:e,positions:e.map(function(t){return a-t*i}),scaleMultiplier:i,zeroLine:a},this.calcDatasetPoints(),this.calcYExtremes(),this.calcYRegions()}},{key:"calcDatasetPoints",value:function(){var t=this.state,e=function(e){return e.map(function(e){return Dt(e,t.yAxis)})};t.datasets=this.data.datasets.map(function(t,i){var n=t.values,a=t.cumulativeYs||[];return{name:t.name&&t.name.replace(/<|>|&/g,function(t){return"&"==t?"&":"<"==t?"<":">"}),index:i,chartType:t.chartType,values:n,yPositions:e(n),cumulativeYs:a,cumulativeYPos:e(a)}})}},{key:"calcYExtremes",value:function(){var t=this.state;if(this.barOptions.stacked)return void(t.yExtremes=t.datasets[t.datasets.length-1].cumulativeYPos);t.yExtremes=new Array(t.datasetLength).fill(9999),t.datasets.map(function(e){e.yPositions.map(function(e,i){er(n)?t.mapTooltipXPosition(s):t.tip.hideTip()})}},{key:"mapTooltipXPosition",value:function(t){var e=this.state;if(e.yExtremes){var i=Nt(t,e.xAxis.positions,!0);if(i>=0){var n=this.dataByIndex[i];this.tip.setValues(n.xPos+this.tip.offset.x,n.yExtreme+this.tip.offset.y,{name:n.formattedLabel,value:""},n.values,i),this.tip.showTip()}}}},{key:"renderLegend",value:function(){var t=this,e=this.data;e.datasets.length>1&&(this.legendArea.textContent="",e.datasets.map(function(e,i){var n=I(100*i,"0",100,t.colors[i],e.name,t.config.truncateLegends);t.legendArea.appendChild(n)}))}},{key:"makeOverlay",value:function(){var t=this;if(this.init)return void(this.init=0);this.overlayGuides&&this.overlayGuides.forEach(function(t){var e=t.overlay;e.parentNode.removeChild(e)}),this.overlayGuides=this.dataUnitComponents.map(function(t){return{type:t.unitType,overlay:void 0,units:t.units}}),void 0===this.state.currentIndex&&(this.state.currentIndex=this.state.datasetLength-1),this.overlayGuides.map(function(e){var i=e.units[t.state.currentIndex];e.overlay=ue[e.type](i),t.drawArea.appendChild(e.overlay)})}},{key:"updateOverlayGuides",value:function(){this.overlayGuides&&this.overlayGuides.forEach(function(t){var e=t.overlay;e.parentNode.removeChild(e)})}},{key:"bindOverlay",value:function(){var t=this;this.parent.addEventListener("data-select",function(){t.updateOverlay()})}},{key:"bindUnits",value:function(){var t=this;this.dataUnitComponents.map(function(e){e.units.map(function(e){e.addEventListener("click",function(){var i=e.getAttribute("data-point-index");t.setCurrentDataPoint(i)})})}),this.tip.container.addEventListener("click",function(){var e=t.tip.container.getAttribute("data-point-index");t.setCurrentDataPoint(e)})}},{key:"updateOverlay",value:function(){var t=this;this.overlayGuides.map(function(e){var i=e.units[t.state.currentIndex];he[e.type](i,e.overlay)})}},{key:"onLeftArrow",value:function(){this.setCurrentDataPoint(this.state.currentIndex-1)}},{key:"onRightArrow",value:function(){this.setCurrentDataPoint(this.state.currentIndex+1)}},{key:"getDataPoint",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.state.currentIndex,e=this.state;return{index:t,label:e.xAxis.labels[t],values:e.datasets.map(function(e){return e.values[t]})}}},{key:"setCurrentDataPoint",value:function(t){var e=this.state;(t=parseInt(t))<0&&(t=0),t>=e.xAxis.labels.length&&(t=e.xAxis.labels.length-1),t!==e.currentIndex&&(e.currentIndex=t,s(this.parent,"data-select",this.getDataPoint()))}},{key:"addDataPoint",value:function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:this.state.datasetLength;Rt(i.prototype.__proto__||Object.getPrototypeOf(i.prototype),"addDataPoint",this).call(this,t,e,n),this.data.labels.splice(n,0,t),this.data.datasets.map(function(t,i){t.values.splice(n,0,e[i])}),this.update(this.data)}},{key:"removeDataPoint",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.state.datasetLength-1;this.data.labels.length<=1||(Rt(i.prototype.__proto__||Object.getPrototypeOf(i.prototype),"removeDataPoint",this).call(this,t),this.data.labels.splice(t,1),this.data.datasets.map(function(e){e.values.splice(t,1)}),this.update(this.data))}},{key:"updateDataset",value:function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0;this.data.datasets[e].values=t,this.update(this.data)}},{key:"updateDatasets",value:function(t){this.data.datasets.map(function(e,i){t[i]&&(e.values=t[i])}),this.update(this.data)}}]),i}(ye),Ne=function(t){function i(t,e){Ht(this,i);var n=Bt(this,(i.__proto__||Object.getPrototypeOf(i)).call(this,t,e));return n.type="donut",n.initTimeout=0,n.init=1,n.setup(),n}return Yt(i,t),It(i,[{key:"configure",value:function(t){Rt(i.prototype.__proto__||Object.getPrototypeOf(i.prototype),"configure",this).call(this,t),this.mouseMove=this.mouseMove.bind(this),this.mouseLeave=this.mouseLeave.bind(this),this.hoverRadio=t.hoverRadio||.1,this.config.startAngle=t.startAngle||0,this.clockWise=t.clockWise||!1,this.strokeWidth=t.strokeWidth||30}},{key:"calc",value:function(){var t=this;Rt(i.prototype.__proto__||Object.getPrototypeOf(i.prototype),"calc",this).call(this);var e=this.state;this.radius=this.height>this.width?this.center.x-this.strokeWidth/2:this.center.y-this.strokeWidth/2;var n=this.radius,a=this.clockWise,s=e.slicesProperties||[];e.sliceStrings=[],e.slicesProperties=[];var r=180-this.config.startAngle;e.sliceTotals.map(function(i,o){var l=r,u=i/e.grandTotal*360,h=u>180?1:0,c=a?-u:u,d=r+=c,f=p(l,n),v=p(d,n),g=t.init&&s[o],m=void 0,y=void 0;t.init?(m=g?g.startPosition:f,y=g?g.endPosition:f):(m=f,y=v);var b=360===u?W(m,y,t.center,t.radius,t.clockWise,h):z(m,y,t.center,t.radius,t.clockWise,h);e.sliceStrings.push(b),e.slicesProperties.push({startPosition:f,endPosition:v,value:i,total:e.grandTotal,startAngle:l,endAngle:d,angle:c})}),this.init=0}},{key:"setupComponents",value:function(){var t=this.state,e=[["donutSlices",{},function(){return{sliceStrings:t.sliceStrings,colors:this.colors,strokeWidth:this.strokeWidth}}.bind(this)]];this.components=new Map(e.map(function(t){var e=wt.apply(void 0,Ut(t));return[t[0],e]}))}},{key:"calTranslateByAngle",value:function(t){var e=this.radius,i=this.hoverRadio,n=p(t.startAngle+t.angle/2,e);return"translate3d("+n.x*i+"px,"+n.y*i+"px,0)"}},{key:"hoverSlice",value:function(t,i,n,a){if(t){var s=this.colors[i];if(n){ot(t,this.calTranslateByAngle(this.state.slicesProperties[i])),t.style.stroke=A(s,50);var r=e(this.svg),o=a.pageX-r.left+10,l=a.pageY-r.top-10,u=(this.formatted_labels&&this.formatted_labels.length>0?this.formatted_labels[i]:this.state.labels[i])+": ",h=(100*this.state.sliceTotals[i]/this.state.grandTotal).toFixed(1);this.tip.setValues(o,l,{name:u,value:h+"%"}),this.tip.showTip()}else ot(t,"translate3d(0,0,0)"),this.tip.hideTip(),t.style.stroke=s}}},{key:"bindTooltip",value:function(){this.container.addEventListener("mousemove",this.mouseMove),this.container.addEventListener("mouseleave",this.mouseLeave)}},{key:"mouseMove",value:function(t){var e=t.target,i=this.components.get("donutSlices").store,n=this.curActiveSliceIndex,a=this.curActiveSlice;if(i.includes(e)){var s=i.indexOf(e);this.hoverSlice(a,n,!1),this.curActiveSlice=e,this.curActiveSliceIndex=s,this.hoverSlice(e,s,!0,t)}else this.mouseLeave()}},{key:"mouseLeave",value:function(){this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,!1)}}]),i}(be),Se={bar:De,line:De,percentage:Oe,heatmap:Ce,pie:Me,donut:Ne},Ee=function t(e,i){return Ht(this,t),jt(i.type,e,i)},_e=Object.freeze({Chart:Ee,PercentageChart:Oe,PieChart:Me,Heatmap:Ce,AxisChart:De}),ze={};return ze.NAME="Frappe Charts",ze.VERSION="1.6.2",ze=Object.assign({},ze,_e)}); -//# sourceMappingURL=frappe-charts.min.umd.js.map diff --git a/node_modules/frappe-charts/dist/frappe-charts.min.umd.js.map b/node_modules/frappe-charts/dist/frappe-charts.min.umd.js.map deleted file mode 100644 index d7970a8..0000000 --- a/node_modules/frappe-charts/dist/frappe-charts.min.umd.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"frappe-charts.min.umd.js","sources":["../src/js/utils/dom.js","../src/js/utils/constants.js","../src/js/utils/helpers.js","../src/js/utils/draw-utils.js","../src/js/utils/colors.js","../src/js/utils/draw.js","../src/js/utils/animate.js","../src/js/utils/animation.js","../src/js/utils/export.js","../src/js/utils/date-utils.js","../src/js/objects/ChartComponents.js","../src/js/utils/intervals.js","../src/js/utils/axis-chart-utils.js","../src/js/chart.js","../node_modules/style-inject/dist/style-inject.es.js","../src/js/objects/SvgTip.js","../src/css/chartsCss.js","../src/js/charts/BaseChart.js","../src/js/charts/AggregationChart.js","../src/js/charts/PercentageChart.js","../src/js/charts/PieChart.js","../src/js/charts/Heatmap.js","../src/js/charts/AxisChart.js","../src/js/charts/DonutChart.js","../src/js/index.js"],"sourcesContent":["export function $(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\nexport function findNodeIndex(node)\n{\n\tvar i = 0;\n\twhile (node.previousSibling) {\n\t\tnode = node.previousSibling;\n\t\ti++;\n\t}\n\treturn i;\n}\n\n$.create = (tag, o) => {\n\tvar element = document.createElement(tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else if (i in element ) {\n\t\t\telement[i] = val;\n\t\t}\n\t\telse {\n\t\t\telement.setAttribute(i, val);\n\t\t}\n\t}\n\n\treturn element;\n};\n\nexport function getOffset(element) {\n\tlet rect = element.getBoundingClientRect();\n\treturn {\n\t\t// https://stackoverflow.com/a/7436602/6495043\n\t\t// rect.top varies with scroll, so we add whatever has been\n\t\t// scrolled to it to get absolute distance from actual page top\n\t\ttop: rect.top + (document.documentElement.scrollTop || document.body.scrollTop),\n\t\tleft: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft)\n\t};\n}\n\n// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent\n// an element's offsetParent property will return null whenever it, or any of its parents,\n// is hidden via the display style property.\nexport function isHidden(el) {\n\treturn (el.offsetParent === null);\n}\n\nexport function isElementInViewport(el) {\n\t// Although straightforward: https://stackoverflow.com/a/7557433/6495043\n\tvar rect = el.getBoundingClientRect();\n\n\treturn (\n\t\trect.top >= 0 &&\n rect.left >= 0 &&\n rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */\n rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */\n\t);\n}\n\nexport function getElementContentWidth(element) {\n\tvar styles = window.getComputedStyle(element);\n\tvar padding = parseFloat(styles.paddingLeft) +\n\t\tparseFloat(styles.paddingRight);\n\n\treturn element.clientWidth - padding;\n}\n\nexport function bind(element, o){\n\tif (element) {\n\t\tfor (var event in o) {\n\t\t\tvar callback = o[event];\n\n\t\t\tevent.split(/\\s+/).forEach(function (event) {\n\t\t\t\telement.addEventListener(event, callback);\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport function unbind(element, o){\n\tif (element) {\n\t\tfor (var event in o) {\n\t\t\tvar callback = o[event];\n\n\t\t\tevent.split(/\\s+/).forEach(function(event) {\n\t\t\t\telement.removeEventListener(event, callback);\n\t\t\t});\n\t\t}\n\t}\n}\n\nexport function fire(target, type, properties) {\n\tvar evt = document.createEvent(\"HTMLEvents\");\n\n\tevt.initEvent(type, true, true );\n\n\tfor (var j in properties) {\n\t\tevt[j] = properties[j];\n\t}\n\n\treturn target.dispatchEvent(evt);\n}\n\n// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/\nexport function forEachNode(nodeList, callback, scope) {\n\tif(!nodeList) return;\n\tfor (var i = 0; i < nodeList.length; i++) {\n\t\tcallback.call(scope, nodeList[i], i);\n\t}\n}\n\nexport function activate($parent, $child, commonClass, activeClass='active', index = -1) {\n\tlet $children = $parent.querySelectorAll(`.${commonClass}.${activeClass}`);\n\n\tforEachNode($children, (node, i) => {\n\t\tif(index >= 0 && i <= index) return;\n\t\tnode.classList.remove(activeClass);\n\t});\n\n\t$child.classList.add(activeClass);\n}\n","export const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie'];\n\nexport const COMPATIBLE_CHARTS = {\n\tbar: ['line', 'scatter', 'percentage', 'pie'],\n\tline: ['scatter', 'bar', 'percentage', 'pie'],\n\tpie: ['line', 'scatter', 'percentage', 'bar'],\n\tpercentage: ['bar', 'line', 'scatter', 'pie'],\n\theatmap: []\n};\n\nexport const DATA_COLOR_DIVISIONS = {\n\tbar: 'datasets',\n\tline: 'datasets',\n\tpie: 'labels',\n\tpercentage: 'labels',\n\theatmap: HEATMAP_DISTRIBUTION_SIZE\n};\n\nexport const BASE_MEASURES = {\n\tmargins: {\n\t\ttop: 10,\n\t\tbottom: 10,\n\t\tleft: 20,\n\t\tright: 20\n\t},\n\tpaddings: {\n\t\ttop: 20,\n\t\tbottom: 40,\n\t\tleft: 30,\n\t\tright: 10\n\t},\n\n\tbaseHeight: 240,\n\ttitleHeight: 20,\n\tlegendHeight: 30,\n\n\ttitleFontSize: 12,\n};\n\nexport function getTopOffset(m) {\n\treturn m.titleHeight + m.margins.top + m.paddings.top;\n}\n\nexport function getLeftOffset(m) {\n\treturn m.margins.left + m.paddings.left;\n}\n\nexport function getExtraHeight(m) {\n\tlet totalExtraHeight = m.margins.top + m.margins.bottom\n\t\t+ m.paddings.top + m.paddings.bottom\n\t\t+ m.titleHeight + m.legendHeight;\n\treturn totalExtraHeight;\n}\n\nexport function getExtraWidth(m) {\n\tlet totalExtraWidth = m.margins.left + m.margins.right\n\t\t+ m.paddings.left + m.paddings.right;\n\n\treturn totalExtraWidth;\n}\n\nexport const INIT_CHART_UPDATE_TIMEOUT = 700;\nexport const CHART_POST_ANIMATE_TIMEOUT = 400;\n\nexport const DEFAULT_AXIS_CHART_TYPE = 'line';\nexport const AXIS_DATASET_CHART_TYPES = ['line', 'bar'];\n\nexport const AXIS_LEGEND_BAR_SIZE = 100;\n\nexport const BAR_CHART_SPACE_RATIO = 0.5;\nexport const MIN_BAR_PERCENT_HEIGHT = 0.00;\n\nexport const LINE_CHART_DOT_SIZE = 4;\nexport const DOT_OVERLAY_SIZE_INCR = 4;\n\nexport const PERCENTAGE_BAR_DEFAULT_HEIGHT = 20;\nexport const PERCENTAGE_BAR_DEFAULT_DEPTH = 2;\n\n// Fixed 5-color theme,\n// More colors are difficult to parse visually\nexport const HEATMAP_DISTRIBUTION_SIZE = 5;\n\nexport const HEATMAP_SQUARE_SIZE = 10;\nexport const HEATMAP_GUTTER_SIZE = 2;\n\nexport const DEFAULT_CHAR_WIDTH = 7;\n\nexport const TOOLTIP_POINTER_TRIANGLE_HEIGHT = 5;\n\nconst DEFAULT_CHART_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange',\n\t'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey'];\nconst HEATMAP_COLORS_GREEN = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'];\nexport const HEATMAP_COLORS_BLUE = ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e'];\nexport const HEATMAP_COLORS_YELLOW = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c'];\n\nexport const DEFAULT_COLORS = {\n\tbar: DEFAULT_CHART_COLORS,\n\tline: DEFAULT_CHART_COLORS,\n\tpie: DEFAULT_CHART_COLORS,\n\tpercentage: DEFAULT_CHART_COLORS,\n\theatmap: HEATMAP_COLORS_GREEN,\n\tdonut: DEFAULT_CHART_COLORS\n};\n\n// Universal constants\nexport const ANGLE_RATIO = Math.PI / 180;\nexport const FULL_ANGLE = 360;\n","import { ANGLE_RATIO } from './constants';\n\n/**\n * Returns the value of a number upto 2 decimal places.\n * @param {Number} d Any number\n */\nexport function floatTwo(d) {\n\treturn parseFloat(d.toFixed(2));\n}\n\n/**\n * Returns whether or not two given arrays are equal.\n * @param {Array} arr1 First array\n * @param {Array} arr2 Second array\n */\nexport function arraysEqual(arr1, arr2) {\n\tif(arr1.length !== arr2.length) return false;\n\tlet areEqual = true;\n\tarr1.map((d, i) => {\n\t\tif(arr2[i] !== d) areEqual = false;\n\t});\n\treturn areEqual;\n}\n\n/**\n * Shuffles array in place. ES6 version\n * @param {Array} array An array containing the items.\n */\nexport function shuffle(array) {\n\t// Awesomeness: https://bost.ocks.org/mike/shuffle/\n\t// https://stackoverflow.com/a/2450976/6495043\n\t// https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array?noredirect=1&lq=1\n\n\tfor (let i = array.length - 1; i > 0; i--) {\n\t\tlet j = Math.floor(Math.random() * (i + 1));\n\t\t[array[i], array[j]] = [array[j], array[i]];\n\t}\n\n\treturn array;\n}\n\n/**\n * Fill an array with extra points\n * @param {Array} array Array\n * @param {Number} count number of filler elements\n * @param {Object} element element to fill with\n * @param {Boolean} start fill at start?\n */\nexport function fillArray(array, count, element, start=false) {\n\tif(!element) {\n\t\telement = start ? array[0] : array[array.length - 1];\n\t}\n\tlet fillerArray = new Array(Math.abs(count)).fill(element);\n\tarray = start ? fillerArray.concat(array) : array.concat(fillerArray);\n\treturn array;\n}\n\n/**\n * Returns pixel width of string.\n * @param {String} string\n * @param {Number} charWidth Width of single char in pixels\n */\nexport function getStringWidth(string, charWidth) {\n\treturn (string+\"\").length * charWidth;\n}\n\nexport function bindChange(obj, getFn, setFn) {\n\treturn new Proxy(obj, {\n\t\tset: function(target, prop, value) {\n\t\t\tsetFn();\n\t\t\treturn Reflect.set(target, prop, value);\n\t\t},\n\t\tget: function(target, prop) {\n\t\t\tgetFn();\n\t\t\treturn Reflect.get(target, prop);\n\t\t}\n\t});\n}\n\n// https://stackoverflow.com/a/29325222\nexport function getRandomBias(min, max, bias, influence) {\n\tconst range = max - min;\n\tconst biasValue = range * bias + min;\n\tvar rnd = Math.random() * range + min,\t\t// random in range\n\t\tmix = Math.random() * influence;\t\t// random mixer\n\treturn rnd * (1 - mix) + biasValue * mix;\t// mix full range and bias\n}\n\nexport function getPositionByAngle(angle, radius) {\n\treturn {\n\t\tx: Math.sin(angle * ANGLE_RATIO) * radius,\n\t\ty: Math.cos(angle * ANGLE_RATIO) * radius,\n\t};\n}\n\n/**\n * Check if a number is valid for svg attributes\n * @param {object} candidate Candidate to test\n * @param {Boolean} nonNegative flag to treat negative number as invalid\n */\nexport function isValidNumber(candidate, nonNegative=false) {\n\tif (Number.isNaN(candidate)) return false;\n\telse if (candidate === undefined) return false;\n\telse if (!Number.isFinite(candidate)) return false;\n\telse if (nonNegative && candidate < 0) return false;\n\telse return true;\n}\n\n/**\n * Round a number to the closes precision, max max precision 4\n * @param {Number} d Any Number\n */\nexport function round(d) {\n\t// https://floating-point-gui.de/\n\t// https://www.jacklmoore.com/notes/rounding-in-javascript/\n\treturn Number(Math.round(d + 'e4') + 'e-4');\n}\n\n/**\n * Creates a deep clone of an object\n * @param {Object} candidate Any Object\n */\n export function deepClone(candidate) {\n\tlet cloned, value, key;\n \n\tif (candidate instanceof Date) {\n\t return new Date(candidate.getTime());\n\t}\n \n\tif (typeof candidate !== \"object\" || candidate === null) {\n\t return candidate;\n\t}\n \n\tcloned = Array.isArray(candidate) ? [] : {};\n \n\tfor (key in candidate) {\n\t value = candidate[key];\n \n\t cloned[key] = deepClone(value);\n\t}\n \n\treturn cloned;\n }","import { fillArray } from './helpers';\n\nexport function getBarHeightAndYAttr(yTop, zeroLine) {\n\tlet height, y;\n\tif (yTop <= zeroLine) {\n\t\theight = zeroLine - yTop;\n\t\ty = yTop;\n\t} else {\n\t\theight = yTop - zeroLine;\n\t\ty = zeroLine;\n\t}\n\n\treturn [height, y];\n}\n\nexport function equilizeNoOfElements(array1, array2,\n\textraCount = array2.length - array1.length) {\n\n\t// Doesn't work if either has zero elements.\n\tif(extraCount > 0) {\n\t\tarray1 = fillArray(array1, extraCount);\n\t} else {\n\t\tarray2 = fillArray(array2, extraCount);\n\t}\n\treturn [array1, array2];\n}\n\nexport function truncateString(txt, len) {\n\tif (!txt) {\n\t\treturn;\n\t}\n\tif (txt.length > len) {\n\t\treturn txt.slice(0, len-3) + '...';\n\t} else {\n\t\treturn txt;\n\t}\n}\n\nexport function shortenLargeNumber(label) {\n\tlet number;\n\tif (typeof label === 'number') number = label;\n\telse if (typeof label === 'string') {\n\t\tnumber = Number(label);\n\t\tif (Number.isNaN(number)) return label;\n\t}\n\n\t// Using absolute since log wont work for negative numbers\n\tlet p = Math.floor(Math.log10(Math.abs(number)));\n\tif (p <= 2) return number; // Return as is for a 3 digit number of less\n\tlet\tl = Math.floor(p / 3);\n\tlet shortened = (Math.pow(10, p - l * 3) * +(number / Math.pow(10, p)).toFixed(1));\n\n\t// Correct for floating point error upto 2 decimal places\n\treturn Math.round(shortened*100)/100 + ' ' + ['', 'K', 'M', 'B', 'T'][l];\n}\n\n// cubic bezier curve calculation (from example by François Romain)\nexport function getSplineCurvePointsStr(xList, yList) {\n\n\tlet points=[];\n\tfor(let i=0;i {\n\t\tlet lengthX = pointB[0] - pointA[0];\n\t\tlet lengthY = pointB[1] - pointA[1];\n\t\treturn {\n\t\t\tlength: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)),\n\t\t\tangle: Math.atan2(lengthY, lengthX)\n\t\t};\n\t};\n \n\tlet controlPoint = (current, previous, next, reverse) => {\n\t\tlet p = previous || current;\n\t\tlet n = next || current;\n\t\tlet o = line(p, n);\n\t\tlet angle = o.angle + (reverse ? Math.PI : 0);\n\t\tlet length = o.length * smoothing;\n\t\tlet x = current[0] + Math.cos(angle) * length;\n\t\tlet y = current[1] + Math.sin(angle) * length;\n\t\treturn [x, y];\n\t};\n \n\tlet bezierCommand = (point, i, a) => {\n\t\tlet cps = controlPoint(a[i - 1], a[i - 2], point);\n\t\tlet cpe = controlPoint(point, a[i - 1], a[i + 1], true);\n\t\treturn `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`;\n\t};\n \n\tlet pointStr = (points, command) => {\n\t\treturn points.reduce((acc, point, i, a) => i === 0\n\t\t\t? `${point[0]},${point[1]}`\n\t\t\t: `${acc} ${command(point, i, a)}`, '');\n\t};\n \n\treturn pointStr(points, bezierCommand);\n}\n","const PRESET_COLOR_MAP = {\n\t'light-blue': '#7cd6fd',\n\t'blue': '#5e64ff',\n\t'violet': '#743ee2',\n\t'red': '#ff5858',\n\t'orange': '#ffa00a',\n\t'yellow': '#feef72',\n\t'green': '#28a745',\n\t'light-green': '#98d85b',\n\t'purple': '#b554ff',\n\t'magenta': '#ffa3ef',\n\t'black': '#36114C',\n\t'grey': '#bdd3e6',\n\t'light-grey': '#f0f4f7',\n\t'dark-grey': '#b8c2cc'\n};\n\nfunction limitColor(r){\n\tif (r > 255) return 255;\n\telse if (r < 0) return 0;\n\treturn r;\n}\n\nexport function lightenDarkenColor(color, amt) {\n\tlet col = getColor(color);\n\tlet usePound = false;\n\tif (col[0] == \"#\") {\n\t\tcol = col.slice(1);\n\t\tusePound = true;\n\t}\n\tlet num = parseInt(col,16);\n\tlet r = limitColor((num >> 16) + amt);\n\tlet b = limitColor(((num >> 8) & 0x00FF) + amt);\n\tlet g = limitColor((num & 0x0000FF) + amt);\n\treturn (usePound?\"#\":\"\") + (g | (b << 8) | (r << 16)).toString(16);\n}\n\nexport function isValidColor(string) {\n\t// https://stackoverflow.com/a/32685393\n\tlet HEX_RE = /(^\\s*)(#)((?:[A-Fa-f0-9]{3}){1,2})$/i;\n\tlet RGB_RE = /(^\\s*)(rgb|hsl)(a?)[(]\\s*([\\d.]+\\s*%?)\\s*,\\s*([\\d.]+\\s*%?)\\s*,\\s*([\\d.]+\\s*%?)\\s*(?:,\\s*([\\d.]+)\\s*)?[)]$/i;\n\treturn HEX_RE.test(string) || RGB_RE.test(string);\n}\n\nexport const getColor = (color) => {\n\t// When RGB color, convert to hexadecimal (alpha value is omitted)\n\tif((/rgb[a]{0,1}\\([\\d, ]+\\)/gim).test(color)) {\n\t\treturn (/\\D+(\\d*)\\D+(\\d*)\\D+(\\d*)/gim).exec(color)\n\t\t\t.map((x, i) => (i !== 0 ? Number(x).toString(16) : '#'))\n\t\t\t.reduce((c, ch) => `${c}${ch}`);\n\t}\n\treturn PRESET_COLOR_MAP[color] || color;\n};\n","import { getBarHeightAndYAttr, truncateString, shortenLargeNumber, getSplineCurvePointsStr } from './draw-utils';\nimport { getStringWidth, isValidNumber } from './helpers';\nimport { DOT_OVERLAY_SIZE_INCR, PERCENTAGE_BAR_DEFAULT_DEPTH } from './constants';\nimport { lightenDarkenColor } from './colors';\n\nexport const AXIS_TICK_LENGTH = 6;\nconst LABEL_MARGIN = 4;\nconst LABEL_MAX_CHARS = 15;\nexport const FONT_SIZE = 10;\nconst BASE_LINE_COLOR = '#dadada';\nconst FONT_FILL = '#555b51';\n\nfunction $(expr, con) {\n\treturn typeof expr === \"string\"? (con || document).querySelector(expr) : expr || null;\n}\n\nexport function createSVG(tag, o) {\n\tvar element = document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n\n\tfor (var i in o) {\n\t\tvar val = o[i];\n\n\t\tif (i === \"inside\") {\n\t\t\t$(val).appendChild(element);\n\t\t}\n\t\telse if (i === \"around\") {\n\t\t\tvar ref = $(val);\n\t\t\tref.parentNode.insertBefore(element, ref);\n\t\t\telement.appendChild(ref);\n\n\t\t} else if (i === \"styles\") {\n\t\t\tif(typeof val === \"object\") {\n\t\t\t\tObject.keys(val).map(prop => {\n\t\t\t\t\telement.style[prop] = val[prop];\n\t\t\t\t});\n\t\t\t}\n\t\t} else {\n\t\t\tif(i === \"className\") { i = \"class\"; }\n\t\t\tif(i === \"innerHTML\") {\n\t\t\t\telement['textContent'] = val;\n\t\t\t} else {\n\t\t\t\telement.setAttribute(i, val);\n\t\t\t}\n\t\t}\n\t}\n\n\treturn element;\n}\n\nfunction renderVerticalGradient(svgDefElem, gradientId) {\n\treturn createSVG('linearGradient', {\n\t\tinside: svgDefElem,\n\t\tid: gradientId,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: 0,\n\t\ty2: 1\n\t});\n}\n\nfunction setGradientStop(gradElem, offset, color, opacity) {\n\treturn createSVG('stop', {\n\t\t'inside': gradElem,\n\t\t'style': `stop-color: ${color}`,\n\t\t'offset': offset,\n\t\t'stop-opacity': opacity\n\t});\n}\n\nexport function makeSVGContainer(parent, className, width, height) {\n\treturn createSVG('svg', {\n\t\tclassName: className,\n\t\tinside: parent,\n\t\twidth: width,\n\t\theight: height\n\t});\n}\n\nexport function makeSVGDefs(svgContainer) {\n\treturn createSVG('defs', {\n\t\tinside: svgContainer,\n\t});\n}\n\nexport function makeSVGGroup(className, transform='', parent=undefined) {\n\tlet args = {\n\t\tclassName: className,\n\t\ttransform: transform\n\t};\n\tif(parent) args.inside = parent;\n\treturn createSVG('g', args);\n}\n\nexport function wrapInSVGGroup(elements, className='') {\n\tlet g = createSVG('g', {\n\t\tclassName: className\n\t});\n\telements.forEach(e => g.appendChild(e));\n\treturn g;\n}\n\nexport function makePath(pathStr, className='', stroke='none', fill='none', strokeWidth=2) {\n\treturn createSVG('path', {\n\t\tclassName: className,\n\t\td: pathStr,\n\t\tstyles: {\n\t\t\tstroke: stroke,\n\t\t\tfill: fill,\n\t\t\t'stroke-width': strokeWidth\n\t\t}\n\t});\n}\n\nexport function makeArcPathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];\n\treturn `M${center.x} ${center.y}\n\t\tL${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY} z`;\n}\n\nexport function makeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, center.y * 2, center.y + endPosition.y];\n\treturn `M${center.x} ${center.y}\n\t\tL${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${midArc} z\n\t\tL${arcStartX} ${midArc}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY} z`;\n}\n\nexport function makeArcStrokePathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y];\n\n\treturn `M${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY}`;\n}\n\nexport function makeStrokeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){\n\tlet [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y];\n\tlet [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, radius * 2 + arcStartY, center.y + startPosition.y];\n\n\treturn `M${arcStartX} ${arcStartY}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${midArc}\n\t\tM${arcStartX} ${midArc}\n\t\tA ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0}\n\t\t${arcEndX} ${arcEndY}`;\n}\n\nexport function makeGradient(svgDefElem, color, lighter = false) {\n\tlet gradientId ='path-fill-gradient' + '-' + color + '-' +(lighter ? 'lighter' : 'default');\n\tlet gradientDef = renderVerticalGradient(svgDefElem, gradientId);\n\tlet opacities = [1, 0.6, 0.2];\n\tif(lighter) {\n\t\topacities = [0.4, 0.2, 0];\n\t}\n\n\tsetGradientStop(gradientDef, \"0%\", color, opacities[0]);\n\tsetGradientStop(gradientDef, \"50%\", color, opacities[1]);\n\tsetGradientStop(gradientDef, \"100%\", color, opacities[2]);\n\n\treturn gradientId;\n}\n\nexport function percentageBar(x, y, width, height,\n\tdepth=PERCENTAGE_BAR_DEFAULT_DEPTH, fill='none') {\n\n\tlet args = {\n\t\tclassName: 'percentage-bar',\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height,\n\t\tfill: fill,\n\t\tstyles: {\n\t\t\t'stroke': lightenDarkenColor(fill, -25),\n\t\t\t// Diabolically good: https://stackoverflow.com/a/9000859\n\t\t\t// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray\n\t\t\t'stroke-dasharray': `0, ${height + width}, ${width}, ${height}`,\n\t\t\t'stroke-width': depth\n\t\t},\n\t};\n\n\treturn createSVG(\"rect\", args);\n}\n\nexport function heatSquare(className, x, y, size, radius, fill='none', data={}) {\n\tlet args = {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: size,\n\t\theight: size,\n\t\trx: radius,\n\t\tfill: fill\n\t};\n\n\tObject.keys(data).map(key => {\n\t\targs[key] = data[key];\n\t});\n\n\treturn createSVG(\"rect\", args);\n}\n\nexport function legendBar(x, y, size, fill='none', label, truncate=false) {\n\tlabel = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;\n\n\tlet args = {\n\t\tclassName: 'legend-bar',\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: size,\n\t\theight: '2px',\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE * 2) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"rect\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nexport function legendDot(x, y, size, fill='none', label, truncate=false) {\n\tlabel = truncate ? truncateString(label, LABEL_MAX_CHARS) : label;\n\n\tlet args = {\n\t\tclassName: 'legend-dot',\n\t\tcx: 0,\n\t\tcy: 0,\n\t\tr: size,\n\t\tfill: fill\n\t};\n\tlet text = createSVG('text', {\n\t\tclassName: 'legend-dataset-text',\n\t\tx: 0,\n\t\ty: 0,\n\t\tdx: (FONT_SIZE) + 'px',\n\t\tdy: (FONT_SIZE/3) + 'px',\n\t\t'font-size': (FONT_SIZE * 1.2) + 'px',\n\t\t'text-anchor': 'start',\n\t\tfill: FONT_FILL,\n\t\tinnerHTML: label\n\t});\n\n\tlet group = createSVG('g', {\n\t\ttransform: `translate(${x}, ${y})`\n\t});\n\tgroup.appendChild(createSVG(\"circle\", args));\n\tgroup.appendChild(text);\n\n\treturn group;\n}\n\nexport function makeText(className, x, y, content, options = {}) {\n\tlet fontSize = options.fontSize || FONT_SIZE;\n\tlet dy = options.dy !== undefined ? options.dy : (fontSize / 2);\n\tlet fill = options.fill || FONT_FILL;\n\tlet textAnchor = options.textAnchor || 'start';\n\treturn createSVG('text', {\n\t\tclassName: className,\n\t\tx: x,\n\t\ty: y,\n\t\tdy: dy + 'px',\n\t\t'font-size': fontSize + 'px',\n\t\tfill: fill,\n\t\t'text-anchor': textAnchor,\n\t\tinnerHTML: content\n\t});\n}\n\nfunction makeVertLine(x, label, y1, y2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tlet l = createSVG('line', {\n\t\tclassName: 'line-vertical ' + options.className,\n\t\tx1: 0,\n\t\tx2: 0,\n\t\ty1: y1,\n\t\ty2: y2,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: 0,\n\t\ty: y1 > y2 ? y1 + LABEL_MARGIN : y1 - LABEL_MARGIN - FONT_SIZE,\n\t\tdy: FONT_SIZE + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'middle',\n\t\tinnerHTML: label + \"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(${ x }, 0)`\n\t});\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nfunction makeHoriLine(y, label, x1, x2, options={}) {\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.lineType) options.lineType = '';\n\tif (options.shortenNumbers) label = shortenLargeNumber(label);\n\n\tlet className = 'line-horizontal ' + options.className +\n\t\t(options.lineType === \"dashed\" ? \"dashed\": \"\");\n\n\tlet l = createSVG('line', {\n\t\tclassName: className,\n\t\tx1: x1,\n\t\tx2: x2,\n\t\ty1: 0,\n\t\ty2: 0,\n\t\tstyles: {\n\t\t\tstroke: options.stroke\n\t\t}\n\t});\n\n\tlet text = createSVG('text', {\n\t\tx: x1 < x2 ? x1 - LABEL_MARGIN : x1 + LABEL_MARGIN,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / 2 - 2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': x1 < x2 ? 'end' : 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = createSVG('g', {\n\t\ttransform: `translate(0, ${y})`,\n\t\t'stroke-opacity': 1\n\t});\n\n\tif(text === 0 || text === '0') {\n\t\tline.style.stroke = \"rgba(27, 31, 35, 0.6)\";\n\t}\n\n\tline.appendChild(l);\n\tline.appendChild(text);\n\n\treturn line;\n}\n\nexport function yLine(y, label, width, options={}) {\n\tif (!isValidNumber(y)) y = 0;\n\n\tif(!options.pos) options.pos = 'left';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\tlet x1 = -1 * AXIS_TICK_LENGTH;\n\tlet x2 = options.mode === 'span' ? width + AXIS_TICK_LENGTH : 0;\n\n\tif(options.mode === 'tick' && options.pos === 'right') {\n\t\tx1 = width + AXIS_TICK_LENGTH;\n\t\tx2 = width;\n\t}\n\n\t// let offset = options.pos === 'left' ? -1 * options.offset : options.offset;\n\n\tx1 += options.offset;\n\tx2 += options.offset;\n\n\treturn makeHoriLine(y, label, x1, x2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType,\n\t\tshortenNumbers: options.shortenNumbers\n\t});\n}\n\nexport function xLine(x, label, height, options={}) {\n\tif (!isValidNumber(x)) x = 0;\n\n\tif(!options.pos) options.pos = 'bottom';\n\tif(!options.offset) options.offset = 0;\n\tif(!options.mode) options.mode = 'span';\n\tif(!options.stroke) options.stroke = BASE_LINE_COLOR;\n\tif(!options.className) options.className = '';\n\n\t// Draw X axis line in span/tick mode with optional label\n\t// \ty2(span)\n\t// \t\t\t\t\t\t|\n\t// \t\t\t\t\t\t|\n\t//\t\t\t\tx line\t|\n\t//\t\t\t\t\t\t|\n\t// \t\t\t\t\t \t|\n\t// ---------------------+-- y2(tick)\n\t//\t\t\t\t\t\t|\n\t//\t\t\t\t\t\t\ty1\n\n\tlet y1 = height + AXIS_TICK_LENGTH;\n\tlet y2 = options.mode === 'span' ? -1 * AXIS_TICK_LENGTH : height;\n\n\tif(options.mode === 'tick' && options.pos === 'top') {\n\t\t// top axis ticks\n\t\ty1 = -1 * AXIS_TICK_LENGTH;\n\t\ty2 = 0;\n\t}\n\n\treturn makeVertLine(x, label, y1, y2, {\n\t\tstroke: options.stroke,\n\t\tclassName: options.className,\n\t\tlineType: options.lineType\n\t});\n}\n\nexport function yMarker(y, label, width, options={}) {\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label, 5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet line = makeHoriLine(y, '', 0, width, {\n\t\tstroke: options.stroke || BASE_LINE_COLOR,\n\t\tclassName: options.className || '',\n\t\tlineType: options.lineType\n\t});\n\n\tline.appendChild(labelSvg);\n\n\treturn line;\n}\n\nexport function yRegion(y1, y2, width, label, options={}) {\n\t// return a group\n\tlet height = y1 - y2;\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`, // remove class\n\t\tstyles: {\n\t\t\tfill: `rgba(228, 234, 239, 0.49)`,\n\t\t\tstroke: BASE_LINE_COLOR,\n\t\t\t'stroke-dasharray': `${width}, ${height}`\n\t\t},\n\t\t// 'data-point-index': index,\n\t\tx: 0,\n\t\ty: 0,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tif(!options.labelPos) options.labelPos = 'right';\n\tlet x = options.labelPos === 'left' ? LABEL_MARGIN\n\t\t: width - getStringWidth(label+\"\", 4.5) - LABEL_MARGIN;\n\n\tlet labelSvg = createSVG('text', {\n\t\tclassName: 'chart-label',\n\t\tx: x,\n\t\ty: 0,\n\t\tdy: (FONT_SIZE / -2) + 'px',\n\t\t'font-size': FONT_SIZE + 'px',\n\t\t'text-anchor': 'start',\n\t\tinnerHTML: label+\"\"\n\t});\n\n\tlet region = createSVG('g', {\n\t\ttransform: `translate(0, ${y2})`\n\t});\n\n\tregion.appendChild(rect);\n\tregion.appendChild(labelSvg);\n\n\treturn region;\n}\n\nexport function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\n\tif(height === 0) {\n\t\theight = meta.minHeight;\n\t\ty -= meta.minHeight;\n\t}\n\n\t// Preprocess numbers to avoid svg building errors\n\tif (!isValidNumber(x)) x = 0;\n\tif (!isValidNumber(y)) y = 0;\n\tif (!isValidNumber(height, true)) height = 0;\n\tif (!isValidNumber(width, true)) width = 0;\n\n\tlet rect = createSVG('rect', {\n\t\tclassName: `bar mini`,\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tx: x,\n\t\ty: y,\n\t\twidth: width,\n\t\theight: height\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn rect;\n\t} else {\n\t\trect.setAttribute('y', 0);\n\t\trect.setAttribute('x', 0);\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: width/2,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(rect);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nexport function datasetDot(x, y, radius, color, label='', index=0) {\n\tlet dot = createSVG('circle', {\n\t\tstyle: `fill: ${color}`,\n\t\t'data-point-index': index,\n\t\tcx: x,\n\t\tcy: y,\n\t\tr: radius\n\t});\n\n\tlabel += \"\";\n\n\tif(!label && !label.length) {\n\t\treturn dot;\n\t} else {\n\t\tdot.setAttribute('cy', 0);\n\t\tdot.setAttribute('cx', 0);\n\n\t\tlet text = createSVG('text', {\n\t\t\tclassName: 'data-point-value',\n\t\t\tx: 0,\n\t\t\ty: 0,\n\t\t\tdy: (FONT_SIZE / 2 * -1 - radius) + 'px',\n\t\t\t'font-size': FONT_SIZE + 'px',\n\t\t\t'text-anchor': 'middle',\n\t\t\tinnerHTML: label\n\t\t});\n\n\t\tlet group = createSVG('g', {\n\t\t\t'data-point-index': index,\n\t\t\ttransform: `translate(${x}, ${y})`\n\t\t});\n\t\tgroup.appendChild(dot);\n\t\tgroup.appendChild(text);\n\n\t\treturn group;\n\t}\n}\n\nexport function getPaths(xList, yList, color, options={}, meta={}) {\n\tlet pointsList = yList.map((y, i) => (xList[i] + ',' + y));\n\tlet pointsStr = pointsList.join(\"L\");\n\n\t// Spline\n\tif (options.spline)\n\t\tpointsStr = getSplineCurvePointsStr(xList, yList);\n\n\tlet path = makePath(\"M\"+pointsStr, 'line-graph-path', color);\n\n\t// HeatLine\n\tif(options.heatline) {\n\t\tlet gradient_id = makeGradient(meta.svgDefs, color);\n\t\tpath.style.stroke = `url(#${gradient_id})`;\n\t}\n\n\tlet paths = {\n\t\tpath: path\n\t};\n\n\t// Region\n\tif(options.regionFill) {\n\t\tlet gradient_id_region = makeGradient(meta.svgDefs, color, true);\n\n\t\tlet pathStr = \"M\" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`;\n\t\tpaths.region = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`);\n\t}\n\n\treturn paths;\n}\n\nexport let makeOverlay = {\n\t'bar': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\toverlay.style.fill = '#000000';\n\t\toverlay.style.opacity = '0.4';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'dot': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t},\n\n\t'heat_square': (unit) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet overlay = unit.cloneNode();\n\t\tlet radius = unit.getAttribute('r');\n\t\tlet fill = unit.getAttribute('fill');\n\t\toverlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR);\n\t\toverlay.setAttribute('fill', fill);\n\t\toverlay.style.opacity = '0.6';\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t\treturn overlay;\n\t}\n};\n\nexport let updateOverlay = {\n\t'bar': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'rect') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['x', 'y', 'width', 'height'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'dot': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n\n\t'heat_square': (unit, overlay) => {\n\t\tlet transformValue;\n\t\tif(unit.nodeName !== 'circle') {\n\t\t\ttransformValue = unit.getAttribute('transform');\n\t\t\tunit = unit.childNodes[0];\n\t\t}\n\t\tlet attributes = ['cx', 'cy'];\n\t\tObject.values(unit.attributes)\n\t\t\t.filter(attr => attributes.includes(attr.name) && attr.specified)\n\t\t\t.map(attr => {\n\t\t\t\toverlay.setAttribute(attr.name, attr.nodeValue);\n\t\t\t});\n\n\t\tif(transformValue) {\n\t\t\toverlay.setAttribute('transform', transformValue);\n\t\t}\n\t},\n};\n","import { getBarHeightAndYAttr, getSplineCurvePointsStr } from './draw-utils';\n\nexport const UNIT_ANIM_DUR = 350;\nexport const PATH_ANIM_DUR = 350;\nexport const MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR;\nexport const REPLACE_ALL_NEW_DUR = 250;\n\nexport const STD_EASING = 'easein';\n\nexport function translate(unit, oldCoord, newCoord, duration) {\n\tlet old = typeof oldCoord === 'string' ? oldCoord : oldCoord.join(', ');\n\treturn [\n\t\tunit,\n\t\t{transform: newCoord.join(', ')},\n\t\tduration,\n\t\tSTD_EASING,\n\t\t\"translate\",\n\t\t{transform: old}\n\t];\n}\n\nexport function translateVertLine(xLine, newX, oldX) {\n\treturn translate(xLine, [oldX, 0], [newX, 0], MARKER_LINE_ANIM_DUR);\n}\n\nexport function translateHoriLine(yLine, newY, oldY) {\n\treturn translate(yLine, [0, oldY], [0, newY], MARKER_LINE_ANIM_DUR);\n}\n\nexport function animateRegion(rectGroup, newY1, newY2, oldY2) {\n\tlet newHeight = newY1 - newY2;\n\tlet rect = rectGroup.childNodes[0];\n\tlet width = rect.getAttribute(\"width\");\n\tlet rectAnim = [\n\t\trect,\n\t\t{ height: newHeight, 'stroke-dasharray': `${width}, ${newHeight}` },\n\t\tMARKER_LINE_ANIM_DUR,\n\t\tSTD_EASING\n\t];\n\n\tlet groupAnim = translate(rectGroup, [0, oldY2], [0, newY2], MARKER_LINE_ANIM_DUR);\n\treturn [rectAnim, groupAnim];\n}\n\nexport function animateBar(bar, x, yTop, width, offset=0, meta={}) {\n\tlet [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine);\n\ty -= offset;\n\tif(bar.nodeName !== 'rect') {\n\t\tlet rect = bar.childNodes[0];\n\t\tlet rectAnim = [\n\t\t\trect,\n\t\t\t{width: width, height: height},\n\t\t\tUNIT_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\n\t\tlet oldCoordStr = bar.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(bar, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [rectAnim, groupAnim];\n\t} else {\n\t\treturn [[bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nexport function animateDot(dot, x, y) {\n\tif(dot.nodeName !== 'circle') {\n\t\tlet oldCoordStr = dot.getAttribute(\"transform\").split(\"(\")[1].slice(0, -1);\n\t\tlet groupAnim = translate(dot, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR);\n\t\treturn [groupAnim];\n\t} else {\n\t\treturn [[dot, {cx: x, cy: y}, UNIT_ANIM_DUR, STD_EASING]];\n\t}\n\t// dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein);\n}\n\nexport function animatePath(paths, newXList, newYList, zeroLine, spline) {\n\tlet pathComponents = [];\n\tlet pointsStr = newYList.map((y, i) => (newXList[i] + ',' + y)).join(\"L\");\n\n\tif (spline)\n\t\tpointsStr = getSplineCurvePointsStr(newXList, newYList);\n\n\tconst animPath = [paths.path, {d:\"M\" + pointsStr}, PATH_ANIM_DUR, STD_EASING];\n\tpathComponents.push(animPath);\n\n\tif(paths.region) {\n\t\tlet regStartPt = `${newXList[0]},${zeroLine}L`;\n\t\tlet regEndPt = `L${newXList.slice(-1)[0]}, ${zeroLine}`;\n\n\t\tconst animRegion = [\n\t\t\tpaths.region,\n\t\t\t{d:\"M\" + regStartPt + pointsStr + regEndPt},\n\t\t\tPATH_ANIM_DUR,\n\t\t\tSTD_EASING\n\t\t];\n\t\tpathComponents.push(animRegion);\n\t}\n\n\treturn pathComponents;\n}\n\nexport function animatePathStr(oldPath, pathStr) {\n\treturn [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING];\n}\n","// Leveraging SMIL Animations\n\nimport { REPLACE_ALL_NEW_DUR } from './animate';\n\nconst EASING = {\n\tease: \"0.25 0.1 0.25 1\",\n\tlinear: \"0 0 1 1\",\n\t// easein: \"0.42 0 1 1\",\n\teasein: \"0.1 0.8 0.2 1\",\n\teaseout: \"0 0 0.58 1\",\n\teaseinout: \"0.42 0 0.58 1\"\n};\n\nfunction animateSVGElement(element, props, dur, easingType=\"linear\", type=undefined, oldValues={}) {\n\n\tlet animElement = element.cloneNode(true);\n\tlet newElement = element.cloneNode(true);\n\n\tfor(var attributeName in props) {\n\t\tlet animateElement;\n\t\tif(attributeName === 'transform') {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animateTransform\");\n\t\t} else {\n\t\t\tanimateElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"animate\");\n\t\t}\n\t\tlet currentValue = oldValues[attributeName] || element.getAttribute(attributeName);\n\t\tlet value = props[attributeName];\n\n\t\tlet animAttr = {\n\t\t\tattributeName: attributeName,\n\t\t\tfrom: currentValue,\n\t\t\tto: value,\n\t\t\tbegin: \"0s\",\n\t\t\tdur: dur/1000 + \"s\",\n\t\t\tvalues: currentValue + \";\" + value,\n\t\t\tkeySplines: EASING[easingType],\n\t\t\tkeyTimes: \"0;1\",\n\t\t\tcalcMode: \"spline\",\n\t\t\tfill: 'freeze'\n\t\t};\n\n\t\tif(type) {\n\t\t\tanimAttr[\"type\"] = type;\n\t\t}\n\n\t\tfor (var i in animAttr) {\n\t\t\tanimateElement.setAttribute(i, animAttr[i]);\n\t\t}\n\n\t\tanimElement.appendChild(animateElement);\n\n\t\tif(type) {\n\t\t\tnewElement.setAttribute(attributeName, `translate(${value})`);\n\t\t} else {\n\t\t\tnewElement.setAttribute(attributeName, value);\n\t\t}\n\t}\n\n\treturn [animElement, newElement];\n}\n\nexport function transform(element, style) { // eslint-disable-line no-unused-vars\n\telement.style.transform = style;\n\telement.style.webkitTransform = style;\n\telement.style.msTransform = style;\n\telement.style.mozTransform = style;\n\telement.style.oTransform = style;\n}\n\nfunction animateSVG(svgContainer, elements) {\n\tlet newElements = [];\n\tlet animElements = [];\n\n\telements.map(element => {\n\t\tlet unit = element[0];\n\t\tlet parent = unit.parentNode;\n\n\t\tlet animElement, newElement;\n\n\t\telement[0] = unit;\n\t\t[animElement, newElement] = animateSVGElement(...element);\n\n\t\tnewElements.push(newElement);\n\t\tanimElements.push([animElement, parent]);\n\t\t\n\t\tif (parent) {\n\t\t\tparent.replaceChild(animElement, unit);\n\t\t}\n\t});\n\n\tlet animSvg = svgContainer.cloneNode(true);\n\n\tanimElements.map((animElement, i) => {\n\t\tif (animElement[1]) {\n\t\t\tanimElement[1].replaceChild(newElements[i], animElement[0]);\n\t\t\telements[i][0] = newElements[i];\n\t\t}\n\t});\n\n\treturn animSvg;\n}\n\nexport function runSMILAnimation(parent, svgElement, elementsToAnimate) {\n\tif(elementsToAnimate.length === 0) return;\n\n\tlet animSvgElement = animateSVG(svgElement, elementsToAnimate);\n\tif(svgElement.parentNode == parent) {\n\t\tparent.removeChild(svgElement);\n\t\tparent.appendChild(animSvgElement);\n\n\t}\n\n\t// Replace the new svgElement (data has already been replaced)\n\tsetTimeout(() => {\n\t\tif(animSvgElement.parentNode == parent) {\n\t\t\tparent.removeChild(animSvgElement);\n\t\t\tparent.appendChild(svgElement);\n\t\t}\n\t}, REPLACE_ALL_NEW_DUR);\n}\n","import { $ } from '../utils/dom';\nimport { CSSTEXT } from '../../css/chartsCss';\n\nexport function downloadFile(filename, data) {\n\tvar a = document.createElement('a');\n\ta.style = \"display: none\";\n\tvar blob = new Blob(data, {type: \"image/svg+xml; charset=utf-8\"});\n\tvar url = window.URL.createObjectURL(blob);\n\ta.href = url;\n\ta.download = filename;\n\tdocument.body.appendChild(a);\n\ta.click();\n\tsetTimeout(function(){\n\t\tdocument.body.removeChild(a);\n\t\twindow.URL.revokeObjectURL(url);\n\t}, 300);\n}\n\nexport function prepareForExport(svg) {\n\tlet clone = svg.cloneNode(true);\n\tclone.classList.add('chart-container');\n\tclone.setAttribute('xmlns', \"http://www.w3.org/2000/svg\");\n\tclone.setAttribute('xmlns:xlink', \"http://www.w3.org/1999/xlink\");\n\tlet styleEl = $.create('style', {\n\t\t'innerHTML': CSSTEXT\n\t});\n\tclone.insertBefore(styleEl, clone.firstChild);\n\n\tlet container = $.create('div');\n\tcontainer.appendChild(clone);\n\n\treturn container.innerHTML;\n}\n","// Playing around with dates\n\nexport const NO_OF_YEAR_MONTHS = 12;\nexport const NO_OF_DAYS_IN_WEEK = 7;\nexport const DAYS_IN_YEAR = 375;\nexport const NO_OF_MILLIS = 1000;\nexport const SEC_IN_DAY = 86400;\n\nexport const MONTH_NAMES = [\"January\", \"February\", \"March\", \"April\", \"May\",\n\t\"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"];\nexport const MONTH_NAMES_SHORT = [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\",\n\t\"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"];\n\nexport const DAY_NAMES_SHORT = [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"];\nexport const DAY_NAMES = [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\",\n\t\"Thursday\", \"Friday\", \"Saturday\"];\n\n// https://stackoverflow.com/a/11252167/6495043\nfunction treatAsUtc(date) {\n\tlet result = new Date(date);\n\tresult.setMinutes(result.getMinutes() - result.getTimezoneOffset());\n\treturn result;\n}\n\nexport function getYyyyMmDd(date) {\n\tlet dd = date.getDate();\n\tlet mm = date.getMonth() + 1; // getMonth() is zero-based\n\treturn [\n\t\tdate.getFullYear(),\n\t\t(mm>9 ? '' : '0') + mm,\n\t\t(dd>9 ? '' : '0') + dd\n\t].join('-');\n}\n\nexport function clone(date) {\n\treturn new Date(date.getTime());\n}\n\nexport function timestampSec(date) {\n\treturn date.getTime()/NO_OF_MILLIS;\n}\n\nexport function timestampToMidnight(timestamp, roundAhead = false) {\n\tlet midnightTs = Math.floor(timestamp - (timestamp % SEC_IN_DAY));\n\tif(roundAhead) {\n\t\treturn midnightTs + SEC_IN_DAY;\n\t}\n\treturn midnightTs;\n}\n\n// export function getMonthsBetween(startDate, endDate) {}\n\nexport function getWeeksBetween(startDate, endDate) {\n\tlet weekStartDate = setDayToSunday(startDate);\n\treturn Math.ceil(getDaysBetween(weekStartDate, endDate) / NO_OF_DAYS_IN_WEEK);\n}\n\nexport function getDaysBetween(startDate, endDate) {\n\tlet millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS;\n\treturn (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay;\n}\n\nexport function areInSameMonth(startDate, endDate) {\n\treturn startDate.getMonth() === endDate.getMonth()\n\t\t&& startDate.getFullYear() === endDate.getFullYear();\n}\n\nexport function getMonthName(i, short=false) {\n\tlet monthName = MONTH_NAMES[i];\n\treturn short ? monthName.slice(0, 3) : monthName;\n}\n\nexport function getLastDateInMonth (month, year) {\n\treturn new Date(year, month + 1, 0); // 0: last day in previous month\n}\n\n// mutates\nexport function setDayToSunday(date) {\n\tlet newDate = clone(date);\n\tconst day = newDate.getDay();\n\tif(day !== 0) {\n\t\taddDays(newDate, (-1) * day);\n\t}\n\treturn newDate;\n}\n\n// mutates\nexport function addDays(date, numberOfDays) {\n\tdate.setDate(date.getDate() + numberOfDays);\n}\n","import { makeSVGGroup } from '../utils/draw';\nimport { makeText, makePath, xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, percentageBar, getPaths, heatSquare } from '../utils/draw';\nimport { equilizeNoOfElements } from '../utils/draw-utils';\nimport { translateHoriLine, translateVertLine, animateRegion, animateBar,\n\tanimateDot, animatePath, animatePathStr } from '../utils/animate';\nimport { getMonthName } from '../utils/date-utils';\n\nclass ChartComponent {\n\tconstructor({\n\t\tlayerClass = '',\n\t\tlayerTransform = '',\n\t\tconstants,\n\n\t\tgetData,\n\t\tmakeElements,\n\t\tanimateElements\n\t}) {\n\t\tthis.layerTransform = layerTransform;\n\t\tthis.constants = constants;\n\n\t\tthis.makeElements = makeElements;\n\t\tthis.getData = getData;\n\n\t\tthis.animateElements = animateElements;\n\n\t\tthis.store = [];\n\t\tthis.labels = [];\n\n\t\tthis.layerClass = layerClass;\n\t\tthis.layerClass = typeof(this.layerClass) === 'function'\n\t\t\t? this.layerClass() : this.layerClass;\n\n\t\tthis.refresh();\n\t}\n\n\trefresh(data) {\n\t\tthis.data = data || this.getData();\n\t}\n\n\tsetup(parent) {\n\t\tthis.layer = makeSVGGroup(this.layerClass, this.layerTransform, parent);\n\t}\n\n\tmake() {\n\t\tthis.render(this.data);\n\t\tthis.oldData = this.data;\n\t}\n\n\trender(data) {\n\t\tthis.store = this.makeElements(data);\n\n\t\tthis.layer.textContent = '';\n\t\tthis.store.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t\tthis.labels.forEach(element => {\n\t\t\tthis.layer.appendChild(element);\n\t\t});\n\t}\n\n\tupdate(animate = true) {\n\t\tthis.refresh();\n\t\tlet animateElements = [];\n\t\tif(animate) {\n\t\t\tanimateElements = this.animateElements(this.data) || [];\n\t\t}\n\t\treturn animateElements;\n\t}\n}\n\nlet componentConfigs = {\n\tdonutSlices: {\n\t\tlayerClass: 'donut-slices',\n\t\tmakeElements(data) {\n\t\t\treturn data.sliceStrings.map((s, i) => {\n\t\t\t\tlet slice = makePath(s, 'donut-path', data.colors[i], 'none', data.strokeWidth);\n\t\t\t\tslice.style.transition = 'transform .3s;';\n\t\t\t\treturn slice;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\treturn this.store.map((slice, i) => animatePathStr(slice, newData.sliceStrings[i]));\n\t\t},\n\t},\n\tpieSlices: {\n\t\tlayerClass: 'pie-slices',\n\t\tmakeElements(data) {\n\t\t\treturn data.sliceStrings.map((s, i) =>{\n\t\t\t\tlet slice = makePath(s, 'pie-path', 'none', data.colors[i]);\n\t\t\t\tslice.style.transition = 'transform .3s;';\n\t\t\t\treturn slice;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\treturn this.store.map((slice, i) =>\n\t\t\t\tanimatePathStr(slice, newData.sliceStrings[i])\n\t\t\t);\n\t\t}\n\t},\n\tpercentageBars: {\n\t\tlayerClass: 'percentage-bars',\n\t\tmakeElements(data) {\n\t\t\treturn data.xPositions.map((x, i) =>{\n\t\t\t\tlet y = 0;\n\t\t\t\tlet bar = percentageBar(x, y, data.widths[i],\n\t\t\t\t\tthis.constants.barHeight, this.constants.barDepth, data.colors[i]);\n\t\t\t\treturn bar;\n\t\t\t});\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\tyAxis: {\n\t\tlayerClass: 'y axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\tyLine(position, data.labels[i], this.constants.width,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos, shortenNumbers: this.constants.shortenNumbers})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.labels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tlabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\txAxis: {\n\t\tlayerClass: 'x axis',\n\t\tmakeElements(data) {\n\t\t\treturn data.positions.map((position, i) =>\n\t\t\t\txLine(position, data.calcLabels[i], this.constants.height,\n\t\t\t\t\t{mode: this.constants.mode, pos: this.constants.pos})\n\t\t\t);\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tlet newPos = newData.positions;\n\t\t\tlet newLabels = newData.calcLabels;\n\t\t\tlet oldPos = this.oldData.positions;\n\t\t\tlet oldLabels = this.oldData.calcLabels;\n\n\t\t\t[oldPos, newPos] = equilizeNoOfElements(oldPos, newPos);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\tpositions: oldPos,\n\t\t\t\tcalcLabels: newLabels\n\t\t\t});\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateVertLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyMarkers: {\n\t\tlayerClass: 'y-markers',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(m =>\n\t\t\t\tyMarker(m.position, m.label, this.constants.width,\n\t\t\t\t\t{labelPos: m.options.labelPos, mode: 'span', lineType: 'dashed'})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.position);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.position);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tposition: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\treturn this.store.map((line, i) => {\n\t\t\t\treturn translateHoriLine(\n\t\t\t\t\tline, newPos[i], oldPos[i]\n\t\t\t\t);\n\t\t\t});\n\t\t}\n\t},\n\n\tyRegions: {\n\t\tlayerClass: 'y-regions',\n\t\tmakeElements(data) {\n\t\t\treturn data.map(r =>\n\t\t\t\tyRegion(r.startPos, r.endPos, this.constants.width,\n\t\t\t\t\tr.label, {labelPos: r.options.labelPos})\n\t\t\t);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\t[this.oldData, newData] = equilizeNoOfElements(this.oldData, newData);\n\n\t\t\tlet newPos = newData.map(d => d.endPos);\n\t\t\tlet newLabels = newData.map(d => d.label);\n\t\t\tlet newStarts = newData.map(d => d.startPos);\n\t\t\tlet newOptions = newData.map(d => d.options);\n\n\t\t\tlet oldPos = this.oldData.map(d => d.endPos);\n\t\t\tlet oldStarts = this.oldData.map(d => d.startPos);\n\n\t\t\tthis.render(oldPos.map((pos, i) => {\n\t\t\t\treturn {\n\t\t\t\t\tstartPos: oldStarts[i],\n\t\t\t\t\tendPos: oldPos[i],\n\t\t\t\t\tlabel: newLabels[i],\n\t\t\t\t\toptions: newOptions[i]\n\t\t\t\t};\n\t\t\t}));\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((rectGroup, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateRegion(\n\t\t\t\t\trectGroup, newStarts[i], newPos[i], oldPos[i]\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\theatDomain: {\n\t\tlayerClass: function() { return 'heat-domain domain-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet {index, colWidth, rowHeight, squareSize, radius, xTranslate} = this.constants;\n\t\t\tlet monthNameHeight = -12;\n\t\t\tlet x = xTranslate, y = 0;\n\n\t\t\tthis.serializedSubDomains = [];\n\n\t\t\tdata.cols.map((week, weekNo) => {\n\t\t\t\tif(weekNo === 1) {\n\t\t\t\t\tthis.labels.push(\n\t\t\t\t\t\tmakeText('domain-name', x, monthNameHeight, getMonthName(index, true).toUpperCase(),\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tfontSize: 9\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t)\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tweek.map((day, i) => {\n\t\t\t\t\tif(day.fill) {\n\t\t\t\t\t\tlet data = {\n\t\t\t\t\t\t\t'data-date': day.yyyyMmDd,\n\t\t\t\t\t\t\t'data-value': day.dataValue,\n\t\t\t\t\t\t\t'data-day': i\n\t\t\t\t\t\t};\n\t\t\t\t\t\tlet square = heatSquare('day', x, y, squareSize, radius, day.fill, data);\n\t\t\t\t\t\tthis.serializedSubDomains.push(square);\n\t\t\t\t\t}\n\t\t\t\t\ty += rowHeight;\n\t\t\t\t});\n\t\t\t\ty = 0;\n\t\t\t\tx += colWidth;\n\t\t\t});\n\n\t\t\treturn this.serializedSubDomains;\n\t\t},\n\n\t\tanimateElements(newData) {\n\t\t\tif(newData) return [];\n\t\t}\n\t},\n\n\tbarGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'bar';\n\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\treturn datasetBar(\n\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\ty,\n\t\t\t\t\tdata.barWidth,\n\t\t\t\t\tc.color,\n\t\t\t\t\tdata.labels[j],\n\t\t\t\t\tj,\n\t\t\t\t\tdata.offsets[j],\n\t\t\t\t\t{\n\t\t\t\t\t\tzeroLine: data.zeroLine,\n\t\t\t\t\t\tbarsWidth: data.barsWidth,\n\t\t\t\t\t\tminHeight: c.minHeight\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn this.units;\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newOffsets = newData.offsets;\n\t\t\tlet newLabels = newData.labels;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldOffsets = this.oldData.offsets;\n\t\t\tlet oldLabels = this.oldData.labels;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldOffsets, newOffsets] = equilizeNoOfElements(oldOffsets, newOffsets);\n\t\t\t[oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\toffsets: oldOffsets,\n\t\t\t\tlabels: newLabels,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tbarsWidth: this.oldData.barsWidth,\n\t\t\t\tbarWidth: this.oldData.barWidth,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tthis.store.map((bar, i) => {\n\t\t\t\tanimateElements = animateElements.concat(animateBar(\n\t\t\t\t\tbar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i],\n\t\t\t\t\t{zeroLine: newData.zeroLine}\n\t\t\t\t));\n\t\t\t});\n\n\t\t\treturn animateElements;\n\t\t}\n\t},\n\n\tlineGraph: {\n\t\tlayerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; },\n\t\tmakeElements(data) {\n\t\t\tlet c = this.constants;\n\t\t\tthis.unitType = 'dot';\n\t\t\tthis.paths = {};\n\t\t\tif(!c.hideLine) {\n\t\t\t\tthis.paths = getPaths(\n\t\t\t\t\tdata.xPositions,\n\t\t\t\t\tdata.yPositions,\n\t\t\t\t\tc.color,\n\t\t\t\t\t{\n\t\t\t\t\t\theatline: c.heatline,\n\t\t\t\t\t\tregionFill: c.regionFill,\n\t\t\t\t\t\tspline: c.spline\n\t\t\t\t\t},\n\t\t\t\t\t{\n\t\t\t\t\t\tsvgDefs: c.svgDefs,\n\t\t\t\t\t\tzeroLine: data.zeroLine\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tthis.units = [];\n\t\t\tif(!c.hideDots) {\n\t\t\t\tthis.units = data.yPositions.map((y, j) => {\n\t\t\t\t\treturn datasetDot(\n\t\t\t\t\t\tdata.xPositions[j],\n\t\t\t\t\t\ty,\n\t\t\t\t\t\tdata.radius,\n\t\t\t\t\t\tc.color,\n\t\t\t\t\t\t(c.valuesOverPoints ? data.values[j] : ''),\n\t\t\t\t\t\tj\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn Object.values(this.paths).concat(this.units);\n\t\t},\n\t\tanimateElements(newData) {\n\t\t\tlet newXPos = newData.xPositions;\n\t\t\tlet newYPos = newData.yPositions;\n\t\t\tlet newValues = newData.values;\n\n\t\t\tlet oldXPos = this.oldData.xPositions;\n\t\t\tlet oldYPos = this.oldData.yPositions;\n\t\t\tlet oldValues = this.oldData.values;\n\n\t\t\t[oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos);\n\t\t\t[oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos);\n\t\t\t[oldValues, newValues] = equilizeNoOfElements(oldValues, newValues);\n\n\t\t\tthis.render({\n\t\t\t\txPositions: oldXPos,\n\t\t\t\tyPositions: oldYPos,\n\t\t\t\tvalues: newValues,\n\n\t\t\t\tzeroLine: this.oldData.zeroLine,\n\t\t\t\tradius: this.oldData.radius,\n\t\t\t});\n\n\t\t\tlet animateElements = [];\n\n\t\t\tif(Object.keys(this.paths).length) {\n\t\t\t\tanimateElements = animateElements.concat(animatePath(\n\t\t\t\t\tthis.paths, newXPos, newYPos, newData.zeroLine, this.constants.spline));\n\t\t\t}\n\n\t\t\tif(this.units.length) {\n\t\t\t\tthis.units.map((dot, i) => {\n\t\t\t\t\tanimateElements = animateElements.concat(animateDot(\n\t\t\t\t\t\tdot, newXPos[i], newYPos[i]));\n\t\t\t\t});\n\t\t\t}\n\n\t\t\treturn animateElements;\n\t\t}\n\t}\n};\n\nexport function getComponent(name, constants, getData) {\n\tlet keys = Object.keys(componentConfigs).filter(k => name.includes(k));\n\tlet config = componentConfigs[keys[0]];\n\tObject.assign(config, {\n\t\tconstants: constants,\n\t\tgetData: getData\n\t});\n\treturn new ChartComponent(config);\n}\n","import { floatTwo } from './helpers';\n\nfunction normalize(x) {\n\t// Calculates mantissa and exponent of a number\n\t// Returns normalized number and exponent\n\t// https://stackoverflow.com/q/9383593/6495043\n\n\tif(x===0) {\n\t\treturn [0, 0];\n\t}\n\tif(isNaN(x)) {\n\t\treturn {mantissa: -6755399441055744, exponent: 972};\n\t}\n\tvar sig = x > 0 ? 1 : -1;\n\tif(!isFinite(x)) {\n\t\treturn {mantissa: sig * 4503599627370496, exponent: 972};\n\t}\n\n\tx = Math.abs(x);\n\tvar exp = Math.floor(Math.log10(x));\n\tvar man = x/Math.pow(10, exp);\n\n\treturn [sig * man, exp];\n}\n\nfunction getChartRangeIntervals(max, min=0) {\n\tlet upperBound = Math.ceil(max);\n\tlet lowerBound = Math.floor(min);\n\tlet range = upperBound - lowerBound;\n\n\tlet noOfParts = range;\n\tlet partSize = 1;\n\n\t// To avoid too many partitions\n\tif(range > 5) {\n\t\tif(range % 2 !== 0) {\n\t\t\tupperBound++;\n\t\t\t// Recalc range\n\t\t\trange = upperBound - lowerBound;\n\t\t}\n\t\tnoOfParts = range/2;\n\t\tpartSize = 2;\n\t}\n\n\t// Special case: 1 and 2\n\tif(range <= 2) {\n\t\tnoOfParts = 4;\n\t\tpartSize = range/noOfParts;\n\t}\n\n\t// Special case: 0\n\tif(range === 0) {\n\t\tnoOfParts = 5;\n\t\tpartSize = 1;\n\t}\n\n\tlet intervals = [];\n\tfor(var i = 0; i <= noOfParts; i++){\n\t\tintervals.push(lowerBound + partSize * i);\n\t}\n\treturn intervals;\n}\n\nfunction getChartIntervals(maxValue, minValue=0) {\n\tlet [normalMaxValue, exponent] = normalize(maxValue);\n\tlet normalMinValue = minValue ? minValue/Math.pow(10, exponent): 0;\n\n\t// Allow only 7 significant digits\n\tnormalMaxValue = normalMaxValue.toFixed(6);\n\n\tlet intervals = getChartRangeIntervals(normalMaxValue, normalMinValue);\n\tintervals = intervals.map(value => value * Math.pow(10, exponent));\n\treturn intervals;\n}\n\nexport function calcChartIntervals(values, withMinimum=false) {\n\t//*** Where the magic happens ***\n\n\t// Calculates best-fit y intervals from given values\n\t// and returns the interval array\n\n\tlet maxValue = Math.max(...values);\n\tlet minValue = Math.min(...values);\n\n\t// Exponent to be used for pretty print\n\tlet exponent = 0, intervals = []; // eslint-disable-line no-unused-vars\n\n\tfunction getPositiveFirstIntervals(maxValue, absMinValue) {\n\t\tlet intervals = getChartIntervals(maxValue);\n\n\t\tlet intervalSize = intervals[1] - intervals[0];\n\n\t\t// Then unshift the negative values\n\t\tlet value = 0;\n\t\tfor(var i = 1; value < absMinValue; i++) {\n\t\t\tvalue += intervalSize;\n\t\t\tintervals.unshift((-1) * value);\n\t\t}\n\t\treturn intervals;\n\t}\n\n\t// CASE I: Both non-negative\n\n\tif(maxValue >= 0 && minValue >= 0) {\n\t\texponent = normalize(maxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(maxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(maxValue, minValue);\n\t\t}\n\t}\n\n\t// CASE II: Only minValue negative\n\n\telse if(maxValue > 0 && minValue < 0) {\n\t\t// `withMinimum` irrelevant in this case,\n\t\t// We'll be handling both sides of zero separately\n\t\t// (both starting from zero)\n\t\t// Because ceil() and floor() behave differently\n\t\t// in those two regions\n\n\t\tlet absMinValue = Math.abs(minValue);\n\n\t\tif(maxValue >= absMinValue) {\n\t\t\texponent = normalize(maxValue)[1];\n\t\t\tintervals = getPositiveFirstIntervals(maxValue, absMinValue);\n\t\t} else {\n\t\t\t// Mirror: maxValue => absMinValue, then change sign\n\t\t\texponent = normalize(absMinValue)[1];\n\t\t\tlet posIntervals = getPositiveFirstIntervals(absMinValue, maxValue);\n\t\t\tintervals = posIntervals.reverse().map(d => d * (-1));\n\t\t}\n\n\t}\n\n\t// CASE III: Both non-positive\n\n\telse if(maxValue <= 0 && minValue <= 0) {\n\t\t// Mirrored Case I:\n\t\t// Work with positives, then reverse the sign and array\n\n\t\tlet pseudoMaxValue = Math.abs(minValue);\n\t\tlet pseudoMinValue = Math.abs(maxValue);\n\n\t\texponent = normalize(pseudoMaxValue)[1];\n\t\tif(!withMinimum) {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue);\n\t\t} else {\n\t\t\tintervals = getChartIntervals(pseudoMaxValue, pseudoMinValue);\n\t\t}\n\n\t\tintervals = intervals.reverse().map(d => d * (-1));\n\t}\n\n\treturn intervals;\n}\n\nexport function getZeroIndex(yPts) {\n\tlet zeroIndex;\n\tlet interval = getIntervalSize(yPts);\n\tif(yPts.indexOf(0) >= 0) {\n\t\t// the range has a given zero\n\t\t// zero-line on the chart\n\t\tzeroIndex = yPts.indexOf(0);\n\t} else if(yPts[0] > 0) {\n\t\t// Minimum value is positive\n\t\t// zero-line is off the chart: below\n\t\tlet min = yPts[0];\n\t\tzeroIndex = (-1) * min / interval;\n\t} else {\n\t\t// Maximum value is negative\n\t\t// zero-line is off the chart: above\n\t\tlet max = yPts[yPts.length - 1];\n\t\tzeroIndex = (-1) * max / interval + (yPts.length - 1);\n\t}\n\treturn zeroIndex;\n}\n\nexport function getRealIntervals(max, noOfIntervals, min = 0, asc = 1) {\n\tlet range = max - min;\n\tlet part = range * 1.0 / noOfIntervals;\n\tlet intervals = [];\n\n\tfor(var i = 0; i <= noOfIntervals; i++) {\n\t\tintervals.push(min + part * i);\n\t}\n\n\treturn asc ? intervals : intervals.reverse();\n}\n\nexport function getIntervalSize(orderedArray) {\n\treturn orderedArray[1] - orderedArray[0];\n}\n\nexport function getValueRange(orderedArray) {\n\treturn orderedArray[orderedArray.length-1] - orderedArray[0];\n}\n\nexport function scale(val, yAxis) {\n\treturn floatTwo(yAxis.zeroLine - val * yAxis.scaleMultiplier);\n}\n\nexport function isInRange(val, min, max) {\n\treturn val > min && val < max;\n}\n\nexport function isInRange2D(coord, minCoord, maxCoord) {\n\treturn isInRange(coord[0], minCoord[0], maxCoord[0])\n\t\t&& isInRange(coord[1], minCoord[1], maxCoord[1]);\n}\n\nexport function getClosestInArray(goal, arr, index = false) {\n\tlet closest = arr.reduce(function(prev, curr) {\n\t\treturn (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev);\n\t}, []);\n\n\treturn index ? arr.indexOf(closest) : closest;\n}\n\nexport function calcDistribution(values, distributionSize) {\n\t// Assume non-negative values,\n\t// implying distribution minimum at zero\n\n\tlet dataMaxValue = Math.max(...values);\n\n\tlet distributionStep = 1 / (distributionSize - 1);\n\tlet distribution = [];\n\n\tfor(var i = 0; i < distributionSize; i++) {\n\t\tlet checkpoint = dataMaxValue * (distributionStep * i);\n\t\tdistribution.push(checkpoint);\n\t}\n\n\treturn distribution;\n}\n\nexport function getMaxCheckpoint(value, distribution) {\n\treturn distribution.filter(d => d < value).length;\n}\n","import { fillArray } from '../utils/helpers';\nimport { DEFAULT_AXIS_CHART_TYPE, AXIS_DATASET_CHART_TYPES, DEFAULT_CHAR_WIDTH } from '../utils/constants';\n\nexport function dataPrep(data, type) {\n\tdata.labels = data.labels || [];\n\n\tlet datasetLength = data.labels.length;\n\n\t// Datasets\n\tlet datasets = data.datasets;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\tif(!datasets) {\n\t\t// default\n\t\tdatasets = [{\n\t\t\tvalues: zeroArray\n\t\t}];\n\t}\n\n\tdatasets.map(d=> {\n\t\t// Set values\n\t\tif(!d.values) {\n\t\t\td.values = zeroArray;\n\t\t} else {\n\t\t\t// Check for non values\n\t\t\tlet vals = d.values;\n\t\t\tvals = vals.map(val => (!isNaN(val) ? val : 0));\n\n\t\t\t// Trim or extend\n\t\t\tif(vals.length > datasetLength) {\n\t\t\t\tvals = vals.slice(0, datasetLength);\n\t\t\t} else {\n\t\t\t\tvals = fillArray(vals, datasetLength - vals.length, 0);\n\t\t\t}\n\t\t\td.values = vals;\n\t\t}\n\n\t\t// Set type\n\t\tif(!d.chartType ) {\n\t\t\tif(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE;\n\t\t\td.chartType = type;\n\t\t}\n\n\t});\n\n\t// Markers\n\n\t// Regions\n\t// data.yRegions = data.yRegions || [];\n\tif(data.yRegions) {\n\t\tdata.yRegions.map(d => {\n\t\t\tif(d.end < d.start) {\n\t\t\t\t[d.start, d.end] = [d.end, d.start];\n\t\t\t}\n\t\t});\n\t}\n\n\treturn data;\n}\n\nexport function zeroDataPrep(realData) {\n\tlet datasetLength = realData.labels.length;\n\tlet zeroArray = new Array(datasetLength).fill(0);\n\n\tlet zeroData = {\n\t\tlabels: realData.labels.slice(0, -1),\n\t\tdatasets: realData.datasets.map(d => {\n\t\t\treturn {\n\t\t\t\tname: '',\n\t\t\t\tvalues: zeroArray.slice(0, -1),\n\t\t\t\tchartType: d.chartType\n\t\t\t};\n\t\t}),\n\t};\n\n\tif(realData.yMarkers) {\n\t\tzeroData.yMarkers = [\n\t\t\t{\n\t\t\t\tvalue: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\tif(realData.yRegions) {\n\t\tzeroData.yRegions = [\n\t\t\t{\n\t\t\t\tstart: 0,\n\t\t\t\tend: 0,\n\t\t\t\tlabel: ''\n\t\t\t}\n\t\t];\n\t}\n\n\treturn zeroData;\n}\n\nexport function getShortenedLabels(chartWidth, labels=[], isSeries=true) {\n\tlet allowedSpace = chartWidth / labels.length;\n\tif(allowedSpace <= 0) allowedSpace = 1;\n\tlet allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH;\n\n\tlet seriesMultiple;\n\tif(isSeries) {\n\t\t// Find the maximum label length for spacing calculations\n\t\tlet maxLabelLength = Math.max(...labels.map(label => label.length));\n\t\tseriesMultiple = Math.ceil(maxLabelLength/allowedLetters);\n\t}\n\n\tlet calcLabels = labels.map((label, i) => {\n\t\tlabel += \"\";\n\t\tif(label.length > allowedLetters) {\n\n\t\t\tif(!isSeries) {\n\t\t\t\tif(allowedLetters-3 > 0) {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters-3) + \" ...\";\n\t\t\t\t} else {\n\t\t\t\t\tlabel = label.slice(0, allowedLetters) + '..';\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif(i % seriesMultiple !== 0) {\n\t\t\t\t\tlabel = \"\";\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn label;\n\t});\n\n\treturn calcLabels;\n}\n","import '../css/charts.scss';\n\n// import MultiAxisChart from './charts/MultiAxisChart';\nimport PercentageChart from './charts/PercentageChart';\nimport PieChart from './charts/PieChart';\nimport Heatmap from './charts/Heatmap';\nimport AxisChart from './charts/AxisChart';\nimport DonutChart from './charts/DonutChart';\n\nconst chartTypes = {\n\tbar: AxisChart,\n\tline: AxisChart,\n\t// multiaxis: MultiAxisChart,\n\tpercentage: PercentageChart,\n\theatmap: Heatmap,\n\tpie: PieChart,\n\tdonut: DonutChart,\n};\n\nfunction getChartByType(chartType = 'line', parent, options) {\n\tif (chartType === 'axis-mixed') {\n\t\toptions.type = 'line';\n\t\treturn new AxisChart(parent, options);\n\t}\n\n\tif (!chartTypes[chartType]) {\n\t\tconsole.error(\"Undefined chart type: \" + chartType);\n\t\treturn;\n\t}\n\n\treturn new chartTypes[chartType](parent, options);\n}\n\nclass Chart {\n\tconstructor(parent, options) {\n\t\treturn getChartByType(options.type, parent, options);\n\t}\n}\n\nexport { Chart, PercentageChart, PieChart, Heatmap, AxisChart };","function styleInject(css, ref) {\n if ( ref === void 0 ) ref = {};\n var insertAt = ref.insertAt;\n\n if (!css || typeof document === 'undefined') { return; }\n\n var head = document.head || document.getElementsByTagName('head')[0];\n var style = document.createElement('style');\n style.type = 'text/css';\n\n if (insertAt === 'top') {\n if (head.firstChild) {\n head.insertBefore(style, head.firstChild);\n } else {\n head.appendChild(style);\n }\n } else {\n head.appendChild(style);\n }\n\n if (style.styleSheet) {\n style.styleSheet.cssText = css;\n } else {\n style.appendChild(document.createTextNode(css));\n }\n}\n\nexport default styleInject;\n","import { $ } from '../utils/dom';\nimport { TOOLTIP_POINTER_TRIANGLE_HEIGHT } from '../utils/constants';\n\nexport default class SvgTip {\n\tconstructor({\n\t\tparent = null,\n\t\tcolors = []\n\t}) {\n\t\tthis.parent = parent;\n\t\tthis.colors = colors;\n\t\tthis.titleName = '';\n\t\tthis.titleValue = '';\n\t\tthis.listValues = [];\n\t\tthis.titleValueFirst = 0;\n\n\t\tthis.x = 0;\n\t\tthis.y = 0;\n\n\t\tthis.top = 0;\n\t\tthis.left = 0;\n\n\t\tthis.setup();\n\t}\n\n\tsetup() {\n\t\tthis.makeTooltip();\n\t}\n\n\trefresh() {\n\t\tthis.fill();\n\t\tthis.calcPosition();\n\t}\n\n\tmakeTooltip() {\n\t\tthis.container = $.create('div', {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'graph-svg-tip comparison',\n\t\t\tinnerHTML: `\n\t\t\t\t
                \n\t\t\t\t
                `\n\t\t});\n\t\tthis.hideTip();\n\n\t\tthis.title = this.container.querySelector('.title');\n\t\tthis.dataPointList = this.container.querySelector('.data-point-list');\n\n\t\tthis.parent.addEventListener('mouseleave', () => {\n\t\t\tthis.hideTip();\n\t\t});\n\t}\n\n\tfill() {\n\t\tlet title;\n\t\tif(this.index) {\n\t\t\tthis.container.setAttribute('data-point-index', this.index);\n\t\t}\n\t\tif(this.titleValueFirst) {\n\t\t\ttitle = `${this.titleValue}${this.titleName}`;\n\t\t} else {\n\t\t\ttitle = `${this.titleName}${this.titleValue}`;\n\t\t}\n\t\tthis.title.innerHTML = title;\n\t\tthis.dataPointList.innerHTML = '';\n\n\t\tthis.listValues.map((set, i) => {\n\t\t\tconst color = this.colors[i] || 'black';\n\t\t\tlet value = set.formatted === 0 || set.formatted ? set.formatted : set.value;\n\n\t\t\tlet li = $.create('li', {\n\t\t\t\tstyles: {\n\t\t\t\t\t'border-top': `3px solid ${color}`\n\t\t\t\t},\n\t\t\t\tinnerHTML: `${ value === 0 || value ? value : '' }\n\t\t\t\t\t${set.title ? set.title : '' }`\n\t\t\t});\n\n\t\t\tthis.dataPointList.appendChild(li);\n\t\t});\n\t}\n\n\tcalcPosition() {\n\t\tlet width = this.container.offsetWidth;\n\n\t\tthis.top = this.y - this.container.offsetHeight\n\t\t\t- TOOLTIP_POINTER_TRIANGLE_HEIGHT;\n\t\tthis.left = this.x - width/2;\n\t\tlet maxLeft = this.parent.offsetWidth - width;\n\n\t\tlet pointer = this.container.querySelector('.svg-pointer');\n\n\t\tif(this.left < 0) {\n\t\t\tpointer.style.left = `calc(50% - ${-1 * this.left}px)`;\n\t\t\tthis.left = 0;\n\t\t} else if(this.left > maxLeft) {\n\t\t\tlet delta = this.left - maxLeft;\n\t\t\tlet pointerOffset = `calc(50% + ${delta}px)`;\n\t\t\tpointer.style.left = pointerOffset;\n\n\t\t\tthis.left = maxLeft;\n\t\t} else {\n\t\t\tpointer.style.left = `50%`;\n\t\t}\n\t}\n\n\tsetValues(x, y, title = {}, listValues = [], index = -1) {\n\t\tthis.titleName = title.name;\n\t\tthis.titleValue = title.value;\n\t\tthis.listValues = listValues;\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.titleValueFirst = title.valueFirst || 0;\n\t\tthis.index = index;\n\t\tthis.refresh();\n\t}\n\n\thideTip() {\n\t\tthis.container.style.top = '0px';\n\t\tthis.container.style.left = '0px';\n\t\tthis.container.style.opacity = '0';\n\t}\n\n\tshowTip() {\n\t\tthis.container.style.top = this.top + 'px';\n\t\tthis.container.style.left = this.left + 'px';\n\t\tthis.container.style.opacity = '1';\n\t}\n}\n","export const CSSTEXT = \".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}\";","import SvgTip from '../objects/SvgTip';\nimport { $, isElementInViewport, getElementContentWidth, isHidden } from '../utils/dom';\nimport { makeSVGContainer, makeSVGDefs, makeSVGGroup, makeText } from '../utils/draw';\nimport { BASE_MEASURES, getExtraHeight, getExtraWidth, getTopOffset, getLeftOffset,\n\tINIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS} from '../utils/constants';\nimport { getColor, isValidColor } from '../utils/colors';\nimport { runSMILAnimation } from '../utils/animation';\nimport { downloadFile, prepareForExport } from '../utils/export';\nimport { deepClone } from '../utils/helpers';\n\nexport default class BaseChart {\n\tconstructor(parent, options) {\n\t\t// deepclone options to avoid making changes to orignal object\n\t\toptions = deepClone(options);\n\n\t\tthis.parent = typeof parent === 'string'\n\t\t\t? document.querySelector(parent)\n\t\t\t: parent;\n\n\t\tif (!(this.parent instanceof HTMLElement)) {\n\t\t\tthrow new Error('No `parent` element to render on was provided.');\n\t\t}\n\n\t\tthis.rawChartArgs = options;\n\n\t\tthis.title = options.title || '';\n\t\tthis.type = options.type || '';\n\n\t\tthis.realData = this.prepareData(options.data);\n\t\tthis.data = this.prepareFirstData(this.realData);\n\n\t\tthis.colors = this.validateColors(options.colors, this.type);\n\n\t\tthis.config = {\n\t\t\tshowTooltip: 1, // calculate\n\t\t\tshowLegend: 1, // calculate\n\t\t\tisNavigable: options.isNavigable || 0,\n\t\t\tanimate: (typeof options.animate !== 'undefined') ? options.animate : 1,\n\t\t\ttruncateLegends: options.truncateLegends || 1\n\t\t};\n\n\t\tthis.measures = JSON.parse(JSON.stringify(BASE_MEASURES));\n\t\tlet m = this.measures;\n\t\tthis.setMeasures(options);\n\t\tif(!this.title.length) { m.titleHeight = 0; }\n\t\tif(!this.config.showLegend) m.legendHeight = 0;\n\t\tthis.argHeight = options.height || m.baseHeight;\n\n\t\tthis.state = {};\n\t\tthis.options = {};\n\n\t\tthis.initTimeout = INIT_CHART_UPDATE_TIMEOUT;\n\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.overlays = [];\n\t\t}\n\n\t\tthis.configure(options);\n\t}\n\n\tprepareData(data) {\n\t\treturn data;\n\t}\n\n\tprepareFirstData(data) {\n\t\treturn data;\n\t}\n\n\tvalidateColors(colors, type) {\n\t\tconst validColors = [];\n\t\tcolors = (colors || []).concat(DEFAULT_COLORS[type]);\n\t\tcolors.forEach((string) => {\n\t\t\tconst color = getColor(string);\n\t\t\tif(!isValidColor(color)) {\n\t\t\t\tconsole.warn('\"' + string + '\" is not a valid color.');\n\t\t\t} else {\n\t\t\t\tvalidColors.push(color);\n\t\t\t}\n\t\t});\n\t\treturn validColors;\n\t}\n\n\tsetMeasures() {\n\t\t// Override measures, including those for title and legend\n\t\t// set config for legend and title\n\t}\n\n\tconfigure() {\n\t\tlet height = this.argHeight;\n\t\tthis.baseHeight = height;\n\t\tthis.height = height - getExtraHeight(this.measures);\n\n\t\t// Bind window events\n\t\tthis.boundDrawFn = () => this.draw(true);\n\t\tif (ResizeObserver) {\n\t\t\tthis.resizeObserver = new ResizeObserver(this.boundDrawFn);\n\t\t\tthis.resizeObserver.observe(this.parent);\n\t\t}\n\t\twindow.addEventListener('resize', this.boundDrawFn);\n\t\twindow.addEventListener('orientationchange', this.boundDrawFn);\n\t}\n\n\tdestroy() {\n\t\tif (this.resizeObserver) this.resizeObserver.disconnect();\n\t\twindow.removeEventListener('resize', this.boundDrawFn);\n\t\twindow.removeEventListener('orientationchange', this.boundDrawFn);\n\t}\n\n\t// Has to be called manually\n\tsetup() {\n\t\tthis.makeContainer();\n\t\tthis.updateWidth();\n\t\tthis.makeTooltip();\n\n\t\tthis.draw(false, true);\n\t}\n\n\tmakeContainer() {\n\t\t// Chart needs a dedicated parent element\n\t\tthis.parent.innerHTML = '';\n\n\t\tlet args = {\n\t\t\tinside: this.parent,\n\t\t\tclassName: 'chart-container'\n\t\t};\n\n\t\tif(this.independentWidth) {\n\t\t\targs.styles = { width: this.independentWidth + 'px' };\n\t\t}\n\n\t\tthis.container = $.create('div', args);\n\t}\n\n\tmakeTooltip() {\n\t\tthis.tip = new SvgTip({\n\t\t\tparent: this.container,\n\t\t\tcolors: this.colors\n\t\t});\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {}\n\n\tdraw(onlyWidthChange=false, init=false) {\n\t\tif (onlyWidthChange && isHidden(this.parent)) {\n\t\t\t// Don't update anything if the chart is hidden\n\t\t\treturn;\n\t\t}\n\t\tthis.updateWidth();\n\n\t\tthis.calc(onlyWidthChange);\n\t\tthis.makeChartArea();\n\t\tthis.setupComponents();\n\n\t\tthis.components.forEach(c => c.setup(this.drawArea));\n\t\t// this.components.forEach(c => c.make());\n\t\tthis.render(this.components, false);\n\n\t\tif(init) {\n\t\t\tthis.data = this.realData;\n\t\t\tsetTimeout(() => {this.update(this.data);}, this.initTimeout);\n\t\t}\n\n\t\tthis.renderLegend();\n\n\t\tthis.setupNavigation(init);\n\t}\n\n\tcalc() {} // builds state\n\n\tupdateWidth() {\n\t\tthis.baseWidth = getElementContentWidth(this.parent);\n\t\tthis.width = this.baseWidth - getExtraWidth(this.measures);\n\t}\n\n\tmakeChartArea() {\n\t\tif(this.svg) {\n\t\t\tthis.container.removeChild(this.svg);\n\t\t}\n\t\tlet m = this.measures;\n\n\t\tthis.svg = makeSVGContainer(\n\t\t\tthis.container,\n\t\t\t'frappe-chart chart',\n\t\t\tthis.baseWidth,\n\t\t\tthis.baseHeight\n\t\t);\n\t\tthis.svgDefs = makeSVGDefs(this.svg);\n\n\t\tif(this.title.length) {\n\t\t\tthis.titleEL = makeText(\n\t\t\t\t'title',\n\t\t\t\tm.margins.left,\n\t\t\t\tm.margins.top,\n\t\t\t\tthis.title,\n\t\t\t\t{\n\t\t\t\t\tfontSize: m.titleFontSize,\n\t\t\t\t\tfill: '#666666',\n\t\t\t\t\tdy: m.titleFontSize\n\t\t\t\t}\n\t\t\t);\n\t\t}\n\n\t\tlet top = getTopOffset(m);\n\t\tthis.drawArea = makeSVGGroup(\n\t\t\tthis.type + '-chart chart-draw-area',\n\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t);\n\n\t\tif(this.config.showLegend) {\n\t\t\ttop += this.height + m.paddings.bottom;\n\t\t\tthis.legendArea = makeSVGGroup(\n\t\t\t\t'chart-legend',\n\t\t\t\t`translate(${getLeftOffset(m)}, ${top})`\n\t\t\t);\n\t\t}\n\n\t\tif(this.title.length) { this.svg.appendChild(this.titleEL); }\n\t\tthis.svg.appendChild(this.drawArea);\n\t\tif(this.config.showLegend) { this.svg.appendChild(this.legendArea); }\n\n\t\tthis.updateTipOffset(getLeftOffset(m), getTopOffset(m));\n\t}\n\n\tupdateTipOffset(x, y) {\n\t\tthis.tip.offset = {\n\t\t\tx: x,\n\t\t\ty: y\n\t\t};\n\t}\n\n\tsetupComponents() { this.components = new Map(); }\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\t\tthis.data = this.prepareData(data);\n\t\tthis.calc(); // builds state\n\t\tthis.render(this.components, this.config.animate);\n\t\tthis.renderLegend();\n\t}\n\n\trender(components=this.components, animate=true) {\n\t\tif(this.config.isNavigable) {\n\t\t\t// Remove all existing overlays\n\t\t\tthis.overlays.map(o => o.parentNode.removeChild(o));\n\t\t\t// ref.parentNode.insertBefore(element, ref);\n\t\t}\n\t\tlet elementsToAnimate = [];\n\t\t// Can decouple to this.refreshComponents() first to save animation timeout\n\t\tcomponents.forEach(c => {\n\t\t\telementsToAnimate = elementsToAnimate.concat(c.update(animate));\n\t\t});\n\t\tif(elementsToAnimate.length > 0) {\n\t\t\trunSMILAnimation(this.container, this.svg, elementsToAnimate);\n\t\t\tsetTimeout(() => {\n\t\t\t\tcomponents.forEach(c => c.make());\n\t\t\t\tthis.updateNav();\n\t\t\t}, CHART_POST_ANIMATE_TIMEOUT);\n\t\t} else {\n\t\t\tcomponents.forEach(c => c.make());\n\t\t\tthis.updateNav();\n\t\t}\n\t}\n\n\tupdateNav() {\n\t\tif(this.config.isNavigable) {\n\t\t\tthis.makeOverlay();\n\t\t\tthis.bindUnits();\n\t\t}\n\t}\n\n\trenderLegend() {}\n\n\tsetupNavigation(init=false) {\n\t\tif(!this.config.isNavigable) return;\n\n\t\tif(init) {\n\t\t\tthis.bindOverlay();\n\n\t\t\tthis.keyActions = {\n\t\t\t\t'13': this.onEnterKey.bind(this),\n\t\t\t\t'37': this.onLeftArrow.bind(this),\n\t\t\t\t'38': this.onUpArrow.bind(this),\n\t\t\t\t'39': this.onRightArrow.bind(this),\n\t\t\t\t'40': this.onDownArrow.bind(this),\n\t\t\t};\n\n\t\t\tdocument.addEventListener('keydown', (e) => {\n\t\t\t\tif(isElementInViewport(this.container)) {\n\t\t\t\t\te = e || window.event;\n\t\t\t\t\tif(this.keyActions[e.keyCode]) {\n\t\t\t\t\t\tthis.keyActions[e.keyCode]();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t}\n\n\tmakeOverlay() {}\n\tupdateOverlay() {}\n\tbindOverlay() {}\n\tbindUnits() {}\n\n\tonLeftArrow() {}\n\tonRightArrow() {}\n\tonUpArrow() {}\n\tonDownArrow() {}\n\tonEnterKey() {}\n\n\taddDataPoint() {}\n\tremoveDataPoint() {}\n\n\tgetDataPoint() {}\n\tsetCurrentDataPoint() {}\n\n\tupdateDataset() {}\n\n\texport() {\n\t\tlet chartSvg = prepareForExport(this.svg);\n\t\tdownloadFile(this.title || 'Chart', [chartSvg]);\n\t}\n}\n","import BaseChart from './BaseChart';\nimport { truncateString } from '../utils/draw-utils';\nimport { legendDot } from '../utils/draw';\nimport { round } from '../utils/helpers';\nimport { getExtraWidth } from '../utils/constants';\n\nexport default class AggregationChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\n\t\tthis.config.formatTooltipY = (args.tooltipOptions || {}).formatTooltipY;\n\t\tthis.config.maxSlices = args.maxSlices || 20;\n\t\tthis.config.maxLegendPoints = args.maxLegendPoints || 20;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\t\tlet maxSlices = this.config.maxSlices;\n\t\ts.sliceTotals = [];\n\n\t\tlet allTotals = this.data.labels.map((label, i) => {\n\t\t\tlet total = 0;\n\t\t\tthis.data.datasets.map(e => {\n\t\t\t\ttotal += e.values[i];\n\t\t\t});\n\t\t\treturn [total, label];\n\t\t}).filter(d => { return d[0] >= 0; }); // keep only positive results\n\n\t\tlet totals = allTotals;\n\t\tif(allTotals.length > maxSlices) {\n\t\t\t// Prune and keep a grey area for rest as per maxSlices\n\t\t\tallTotals.sort((a, b) => { return b[0] - a[0]; });\n\n\t\t\ttotals = allTotals.slice(0, maxSlices-1);\n\t\t\tlet remaining = allTotals.slice(maxSlices-1);\n\n\t\t\tlet sumOfRemaining = 0;\n\t\t\tremaining.map(d => {sumOfRemaining += d[0];});\n\t\t\ttotals.push([sumOfRemaining, 'Rest']);\n\t\t\tthis.colors[maxSlices-1] = 'grey';\n\t\t}\n\n\t\ts.labels = [];\n\t\ttotals.map(d => {\n\t\t\ts.sliceTotals.push(round(d[0]));\n\t\t\ts.labels.push(d[1]);\n\t\t});\n\n\t\ts.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0);\n\n\t\tthis.center = {\n\t\t\tx: this.width / 2,\n\t\t\ty: this.height / 2\n\t\t};\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.state;\n\t\tthis.legendArea.textContent = '';\n\t\tthis.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints);\n\n\t\tlet count = 0;\n\t\tlet y = 0;\n\t\tthis.legendTotals.map((d, i) => {\n\t\t\tlet barWidth = 150;\n\t\t\tlet divisor = Math.floor(\n\t\t\t\t(this.width - getExtraWidth(this.measures))/barWidth\n\t\t\t);\n\t\t\tif (this.legendTotals.length < divisor) {\n\t\t\t\tbarWidth = this.width/this.legendTotals.length;\n\t\t\t}\n\t\t\tif(count > divisor) {\n\t\t\t\tcount = 0;\n\t\t\t\ty += 20;\n\t\t\t}\n\t\t\tlet x = barWidth * count + 5;\n\t\t\tlet label = this.config.truncateLegends ? truncateString(s.labels[i], barWidth/10) : s.labels[i];\n\t\t\tlet formatted = this.config.formatTooltipY ? this.config.formatTooltipY(d) : d;\n\t\t\tlet dot = legendDot(\n\t\t\t\tx,\n\t\t\t\ty,\n\t\t\t\t5,\n\t\t\t\tthis.colors[i],\n\t\t\t\t`${label}: ${formatted}`,\n\t\t\t\tfalse\n\t\t\t);\n\t\t\tthis.legendArea.appendChild(dot);\n\t\t\tcount++;\n\t\t});\n\t}\n}\n","import AggregationChart from './AggregationChart';\nimport { getOffset } from '../utils/dom';\nimport { getComponent } from '../objects/ChartComponents';\nimport { PERCENTAGE_BAR_DEFAULT_HEIGHT, PERCENTAGE_BAR_DEFAULT_DEPTH } from '../utils/constants';\n\nexport default class PercentageChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'percentage';\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.barOptions = options.barOptions || {};\n\n\t\tlet b = this.barOptions;\n\t\tb.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT;\n\t\tb.depth = b.depth || PERCENTAGE_BAR_DEFAULT_DEPTH;\n\n\t\tm.paddings.right = 30;\n\t\tm.legendHeight = 60;\n\t\tm.baseHeight = (b.height + b.depth * 0.5) * 8;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'percentageBars',\n\t\t\t\t{\n\t\t\t\t\tbarHeight: this.barOptions.height,\n\t\t\t\t\tbarDepth: this.barOptions.depth,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xPositions,\n\t\t\t\t\t\twidths: s.widths,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\n\t\ts.xPositions = [];\n\t\ts.widths = [];\n\n\t\tlet xPos = 0;\n\t\ts.sliceTotals.map((value) => {\n\t\t\tlet width = this.width * value / s.grandTotal;\n\t\t\ts.widths.push(width);\n\t\t\ts.xPositions.push(xPos);\n\t\t\txPos += width;\n\t\t});\n\t}\n\n\tmakeDataByIndex() { }\n\n\tbindTooltip() {\n\t\tlet s = this.state;\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet bars = this.components.get('percentageBars').store;\n\t\t\tlet bar = e.target;\n\t\t\tif(bars.includes(bar)) {\n\n\t\t\t\tlet i = bars.indexOf(bar);\n\t\t\t\tlet gOff = getOffset(this.container), pOff = getOffset(bar);\n\n\t\t\t\tlet x = pOff.left - gOff.left + parseInt(bar.getAttribute('width'))/2;\n\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\tlet title = (this.formattedLabels && this.formattedLabels.length>0\n\t\t\t\t\t? this.formattedLabels[i] : this.state.labels[i]) + ': ';\n\t\t\t\tlet fraction = s.sliceTotals[i]/s.grandTotal;\n\n\t\t\t\tthis.tip.setValues(x, y, {name: title, value: (fraction*100).toFixed(1) + \"%\"});\n\t\t\t\tthis.tip.showTip();\n\t\t\t}\n\t\t});\n\t}\n}\n","import AggregationChart from './AggregationChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset } from '../utils/dom';\nimport { getPositionByAngle } from '../utils/helpers';\nimport { makeArcPathStr, makeCircleStr } from '../utils/draw';\nimport { lightenDarkenColor } from '../utils/colors';\nimport { transform } from '../utils/animation';\nimport { FULL_ANGLE } from '../utils/constants';\n\nexport default class PieChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'pie';\n\t\tthis.initTimeout = 0;\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\t\tthis.mouseMove = this.mouseMove.bind(this);\n\t\tthis.mouseLeave = this.mouseLeave.bind(this);\n\n\t\tthis.hoverRadio = args.hoverRadio || 0.1;\n\t\tthis.config.startAngle = args.startAngle || 0;\n\n\t\tthis.clockWise = args.clockWise || false;\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\t\tthis.radius = (this.height > this.width ? this.center.x : this.center.y);\n\n\t\tconst { radius, clockWise } = this;\n\n\t\tconst prevSlicesProperties = s.slicesProperties || [];\n\t\ts.sliceStrings = [];\n\t\ts.slicesProperties = [];\n\t\tlet curAngle = 180 - this.config.startAngle;\n\t\ts.sliceTotals.map((total, i) => {\n\t\t\tconst startAngle = curAngle;\n\t\t\tconst originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;\n\t\t\tconst largeArc = originDiffAngle > 180 ? 1: 0;\n\t\t\tconst diffAngle = clockWise ? -originDiffAngle : originDiffAngle;\n\t\t\tconst endAngle = curAngle = curAngle + diffAngle;\n\t\t\tconst startPosition = getPositionByAngle(startAngle, radius);\n\t\t\tconst endPosition = getPositionByAngle(endAngle, radius);\n\n\t\t\tconst prevProperty = this.init && prevSlicesProperties[i];\n\n\t\t\tlet curStart,curEnd;\n\t\t\tif(this.init) {\n\t\t\t\tcurStart = prevProperty ? prevProperty.startPosition : startPosition;\n\t\t\t\tcurEnd = prevProperty ? prevProperty.endPosition : startPosition;\n\t\t\t} else {\n\t\t\t\tcurStart = startPosition;\n\t\t\t\tcurEnd = endPosition;\n\t\t\t}\n\t\t\tconst curPath =\n\t\t\t\toriginDiffAngle === 360\n\t\t\t\t\t? makeCircleStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc)\n\t\t\t\t\t: makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc);\n\n\t\t\ts.sliceStrings.push(curPath);\n\t\t\ts.slicesProperties.push({\n\t\t\t\tstartPosition,\n\t\t\t\tendPosition,\n\t\t\t\tvalue: total,\n\t\t\t\ttotal: s.grandTotal,\n\t\t\t\tstartAngle,\n\t\t\t\tendAngle,\n\t\t\t\tangle: diffAngle\n\t\t\t});\n\n\t\t});\n\t\tthis.init = 0;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'pieSlices',\n\t\t\t\t{ },\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsliceStrings: s.sliceStrings,\n\t\t\t\t\t\tcolors: this.colors\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalTranslateByAngle(property){\n\t\tconst{radius,hoverRadio} = this;\n\t\tconst position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);\n\t\treturn `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;\n\t}\n\n\thoverSlice(path,i,flag,e){\n\t\tif(!path) return;\n\t\tconst color = this.colors[i];\n\t\tif(flag) {\n\t\t\ttransform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));\n\t\t\tpath.style.fill = lightenDarkenColor(color, 50);\n\t\t\tlet g_off = getOffset(this.svg);\n\t\t\tlet x = e.pageX - g_off.left + 10;\n\t\t\tlet y = e.pageY - g_off.top - 10;\n\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t\t? this.formatted_labels[i] : this.state.labels[i]) + ': ';\n\t\t\tlet percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);\n\t\t\tthis.tip.setValues(x, y, {name: title, value: percent + \"%\"});\n\t\t\tthis.tip.showTip();\n\t\t} else {\n\t\t\ttransform(path,'translate3d(0,0,0)');\n\t\t\tthis.tip.hideTip();\n\t\t\tpath.style.fill = color;\n\t\t}\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', this.mouseMove);\n\t\tthis.container.addEventListener('mouseleave', this.mouseLeave);\n\t}\n\n\tmouseMove(e){\n\t\tconst target = e.target;\n\t\tlet slices = this.components.get('pieSlices').store;\n\t\tlet prevIndex = this.curActiveSliceIndex;\n\t\tlet prevAcitve = this.curActiveSlice;\n\t\tif(slices.includes(target)) {\n\t\t\tlet i = slices.indexOf(target);\n\t\t\tthis.hoverSlice(prevAcitve, prevIndex,false);\n\t\t\tthis.curActiveSlice = target;\n\t\t\tthis.curActiveSliceIndex = i;\n\t\t\tthis.hoverSlice(target, i, true, e);\n\t\t} else {\n\t\t\tthis.mouseLeave();\n\t\t}\n\t}\n\n\tmouseLeave(){\n\t\tthis.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);\n\t}\n}\n","import BaseChart from './BaseChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { makeText, heatSquare } from '../utils/draw';\nimport { DAY_NAMES_SHORT, addDays, areInSameMonth, getLastDateInMonth, setDayToSunday, getYyyyMmDd, getWeeksBetween, getMonthName, clone,\n\tNO_OF_MILLIS, NO_OF_YEAR_MONTHS, NO_OF_DAYS_IN_WEEK } from '../utils/date-utils';\nimport { calcDistribution, getMaxCheckpoint } from '../utils/intervals';\nimport { getExtraHeight, getExtraWidth, HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE,\n\tHEATMAP_GUTTER_SIZE } from '../utils/constants';\n\nconst COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE;\nconst ROW_HEIGHT = COL_WIDTH;\n// const DAY_INCR = 1;\n\nexport default class Heatmap extends BaseChart {\n\tconstructor(parent, options) {\n\t\tsuper(parent, options);\n\t\tthis.type = 'heatmap';\n\n\t\tthis.countLabel = options.countLabel || '';\n\n\t\tlet validStarts = ['Sunday', 'Monday'];\n\t\tlet startSubDomain = validStarts.includes(options.startSubDomain)\n\t\t\t? options.startSubDomain : 'Sunday';\n\t\tthis.startSubDomainIndex = validStarts.indexOf(startSubDomain);\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures(options) {\n\t\tlet m = this.measures;\n\t\tthis.discreteDomains = options.discreteDomains === 0 ? 0 : 1;\n\n\t\tm.paddings.top = ROW_HEIGHT * 3;\n\t\tm.paddings.bottom = 0;\n\t\tm.legendHeight = ROW_HEIGHT * 2;\n\t\tm.baseHeight = ROW_HEIGHT * NO_OF_DAYS_IN_WEEK\n\t\t\t+ getExtraHeight(m);\n\n\t\tlet d = this.data;\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tthis.independentWidth = (getWeeksBetween(d.start, d.end)\n\t\t\t+ spacing) * COL_WIDTH + getExtraWidth(m);\n\t}\n\n\tupdateWidth() {\n\t\tlet spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0;\n\t\tlet noOfWeeks = this.state.noOfWeeks ? this.state.noOfWeeks : 52;\n\t\tthis.baseWidth = (noOfWeeks + spacing) * COL_WIDTH\n\t\t\t+ getExtraWidth(this.measures);\n\t}\n\n\tprepareData(data=this.data) {\n\t\tif(data.start && data.end && data.start > data.end) {\n\t\t\tthrow new Error('Start date cannot be greater than end date.');\n\t\t}\n\n\t\tif(!data.start) {\n\t\t\tdata.start = new Date();\n\t\t\tdata.start.setFullYear( data.start.getFullYear() - 1 );\n\t\t}\n\t\tif(!data.end) { data.end = new Date(); }\n\t\tdata.dataPoints = data.dataPoints || {};\n\n\t\tif(parseInt(Object.keys(data.dataPoints)[0]) > 100000) {\n\t\t\tlet points = {};\n\t\t\tObject.keys(data.dataPoints).forEach(timestampSec => {\n\t\t\t\tlet date = new Date(timestampSec * NO_OF_MILLIS);\n\t\t\t\tpoints[getYyyyMmDd(date)] = data.dataPoints[timestampSec];\n\t\t\t});\n\t\t\tdata.dataPoints = points;\n\t\t}\n\n\t\treturn data;\n\t}\n\n\tcalc() {\n\t\tlet s = this.state;\n\n\t\ts.start = clone(this.data.start);\n\t\ts.end = clone(this.data.end);\n\n\t\ts.firstWeekStart = clone(s.start);\n\t\ts.noOfWeeks = getWeeksBetween(s.start, s.end);\n\t\ts.distribution = calcDistribution(\n\t\t\tObject.values(this.data.dataPoints), HEATMAP_DISTRIBUTION_SIZE);\n\n\t\ts.domainConfigs = this.getDomains();\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\t\tlet lessCol = this.discreteDomains ? 0 : 1;\n\n\t\tlet componentConfigs = s.domainConfigs.map((config, i) => [\n\t\t\t'heatDomain',\n\t\t\t{\n\t\t\t\tindex: config.index,\n\t\t\t\tcolWidth: COL_WIDTH,\n\t\t\t\trowHeight: ROW_HEIGHT,\n\t\t\t\tsquareSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\tradius: this.rawChartArgs.radius || 0,\n\t\t\t\txTranslate: s.domainConfigs\n\t\t\t\t\t.filter((config, j) => j < i)\n\t\t\t\t\t.map(config => config.cols.length - lessCol)\n\t\t\t\t\t.reduce((a, b) => a + b, 0)\n\t\t\t\t\t* COL_WIDTH\n\t\t\t},\n\t\t\tfunction() {\n\t\t\t\treturn s.domainConfigs[i];\n\t\t\t}.bind(this)\n\n\t\t]);\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map((args, i) => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0] + '-' + i, component];\n\t\t\t})\n\t\t);\n\n\t\tlet y = 0;\n\t\tDAY_NAMES_SHORT.forEach((dayName, i) => {\n\t\t\tif([1, 3, 5].includes(i)) {\n\t\t\t\tlet dayText = makeText('subdomain-name', -COL_WIDTH/2, y, dayName,\n\t\t\t\t\t{\n\t\t\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE,\n\t\t\t\t\t\tdy: 8,\n\t\t\t\t\t\ttextAnchor: 'end'\n\t\t\t\t\t}\n\t\t\t\t);\n\t\t\t\tthis.drawArea.appendChild(dayText);\n\t\t\t}\n\t\t\ty += ROW_HEIGHT;\n\t\t});\n\t}\n\n\tupdate(data) {\n\t\tif(!data) {\n\t\t\tconsole.error('No data to update.');\n\t\t}\n\n\t\tthis.data = this.prepareData(data);\n\t\tthis.draw();\n\t\tthis.bindTooltip();\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tthis.components.forEach(comp => {\n\t\t\t\tlet daySquares = comp.store;\n\t\t\t\tlet daySquare = e.target;\n\t\t\t\tif(daySquares.includes(daySquare)) {\n\n\t\t\t\t\tlet count = daySquare.getAttribute('data-value');\n\t\t\t\t\tlet dateParts = daySquare.getAttribute('data-date').split('-');\n\n\t\t\t\t\tlet month = getMonthName(parseInt(dateParts[1])-1, true);\n\n\t\t\t\t\tlet gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect();\n\n\t\t\t\t\tlet width = parseInt(e.target.getAttribute('width'));\n\t\t\t\t\tlet x = pOff.left - gOff.left + width/2;\n\t\t\t\t\tlet y = pOff.top - gOff.top;\n\t\t\t\t\tlet value = count + ' ' + this.countLabel;\n\t\t\t\t\tlet name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2];\n\n\t\t\t\t\tthis.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []);\n\t\t\t\t\tthis.tip.showTip();\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\trenderLegend() {\n\t\tthis.legendArea.textContent = '';\n\t\tlet x = 0;\n\t\tlet y = ROW_HEIGHT;\n\t\tlet radius = this.rawChartArgs.radius || 0;\n\n\t\tlet lessText = makeText('subdomain-name', x, y, 'Less',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tx = (COL_WIDTH * 2) + COL_WIDTH/2;\n\t\tthis.legendArea.appendChild(lessText);\n\n\t\tthis.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map((color, i) => {\n\t\t\tconst square = heatSquare('heatmap-legend-unit', x + (COL_WIDTH + 3) * i,\n\t\t\t\ty, HEATMAP_SQUARE_SIZE, radius, color);\n\t\t\tthis.legendArea.appendChild(square);\n\t\t});\n\n\t\tlet moreTextX = x + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH/4;\n\t\tlet moreText = makeText('subdomain-name', moreTextX, y, 'More',\n\t\t\t{\n\t\t\t\tfontSize: HEATMAP_SQUARE_SIZE + 1,\n\t\t\t\tdy: 9\n\t\t\t}\n\t\t);\n\t\tthis.legendArea.appendChild(moreText);\n\t}\n\n\tgetDomains() {\n\t\tlet s = this.state;\n\t\tconst [startMonth, startYear] = [s.start.getMonth(), s.start.getFullYear()];\n\t\tconst [endMonth, endYear] = [s.end.getMonth(), s.end.getFullYear()];\n\n\t\tconst noOfMonths = (endMonth - startMonth + 1) + (endYear - startYear) * 12;\n\n\t\tlet domainConfigs = [];\n\n\t\tlet startOfMonth = clone(s.start);\n\t\tfor(var i = 0; i < noOfMonths; i++) {\n\t\t\tlet endDate = s.end;\n\t\t\tif(!areInSameMonth(startOfMonth, s.end)) {\n\t\t\t\tlet [month, year] = [startOfMonth.getMonth(), startOfMonth.getFullYear()];\n\t\t\t\tendDate = getLastDateInMonth(month, year);\n\t\t\t}\n\t\t\tdomainConfigs.push(this.getDomainConfig(startOfMonth, endDate));\n\n\t\t\taddDays(endDate, 1);\n\t\t\tstartOfMonth = endDate;\n\t\t}\n\n\t\treturn domainConfigs;\n\t}\n\n\tgetDomainConfig(startDate, endDate='') {\n\t\tlet [month, year] = [startDate.getMonth(), startDate.getFullYear()];\n\t\tlet startOfWeek = setDayToSunday(startDate); // TODO: Monday as well\n\t\tendDate = clone(endDate) || getLastDateInMonth(month, year);\n\n\t\tlet domainConfig = {\n\t\t\tindex: month,\n\t\t\tcols: []\n\t\t};\n\n\t\taddDays(endDate, 1);\n\t\tlet noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate);\n\n\t\tlet cols = [], col;\n\t\tfor(var i = 0; i < noOfMonthWeeks; i++) {\n\t\t\tcol = this.getCol(startOfWeek, month);\n\t\t\tcols.push(col);\n\n\t\t\tstartOfWeek = new Date(col[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd);\n\t\t\taddDays(startOfWeek, 1);\n\t\t}\n\n\t\tif(col[NO_OF_DAYS_IN_WEEK - 1].dataValue !== undefined) {\n\t\t\taddDays(startOfWeek, 1);\n\t\t\tcols.push(this.getCol(startOfWeek, month, true));\n\t\t}\n\n\t\tdomainConfig.cols = cols;\n\n\t\treturn domainConfig;\n\t}\n\n\tgetCol(startDate, month, empty = false) {\n\t\tlet s = this.state;\n\n\t\t// startDate is the start of week\n\t\tlet currentDate = clone(startDate);\n\t\tlet col = [];\n\n\t\tfor(var i = 0; i < NO_OF_DAYS_IN_WEEK; i++, addDays(currentDate, 1)) {\n\t\t\tlet config = {};\n\n\t\t\t// Non-generic adjustment for entire heatmap, needs state\n\t\t\tlet currentDateWithinData = currentDate >= s.start && currentDate <= s.end;\n\n\t\t\tif(empty || currentDate.getMonth() !== month || !currentDateWithinData) {\n\t\t\t\tconfig.yyyyMmDd = getYyyyMmDd(currentDate);\n\t\t\t} else {\n\t\t\t\tconfig = this.getSubDomainConfig(currentDate);\n\t\t\t}\n\t\t\tcol.push(config);\n\t\t}\n\n\t\treturn col;\n\t}\n\n\tgetSubDomainConfig(date) {\n\t\tlet yyyyMmDd = getYyyyMmDd(date);\n\t\tlet dataValue = this.data.dataPoints[yyyyMmDd];\n\t\tlet config = {\n\t\t\tyyyyMmDd: yyyyMmDd,\n\t\t\tdataValue: dataValue || 0,\n\t\t\tfill: this.colors[getMaxCheckpoint(dataValue, this.state.distribution)]\n\t\t};\n\t\treturn config;\n\t}\n}\n","import BaseChart from './BaseChart';\nimport { dataPrep, zeroDataPrep, getShortenedLabels } from '../utils/axis-chart-utils';\nimport { AXIS_LEGEND_BAR_SIZE } from '../utils/constants';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset, fire } from '../utils/dom';\nimport { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale, getClosestInArray } from '../utils/intervals';\nimport { floatTwo } from '../utils/helpers';\nimport { makeOverlay, updateOverlay, legendBar } from '../utils/draw';\nimport { getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO,\n\tLINE_CHART_DOT_SIZE } from '../utils/constants';\n\nexport default class AxisChart extends BaseChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\n\t\tthis.barOptions = args.barOptions || {};\n\t\tthis.lineOptions = args.lineOptions || {};\n\n\t\tthis.type = args.type || 'line';\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tsetMeasures() {\n\t\tif(this.data.datasets.length <= 1) {\n\t\t\tthis.config.showLegend = 0;\n\t\t\tthis.measures.paddings.bottom = 30;\n\t\t}\n\t}\n\n\tconfigure(options) {\n\t\tsuper.configure(options);\n\n\t\toptions.axisOptions = options.axisOptions || {};\n\t\toptions.tooltipOptions = options.tooltipOptions || {};\n\n\t\tthis.config.xAxisMode = options.axisOptions.xAxisMode || 'span';\n\t\tthis.config.yAxisMode = options.axisOptions.yAxisMode || 'span';\n\t\tthis.config.xIsSeries = options.axisOptions.xIsSeries || 0;\n\t\tthis.config.shortenYAxisNumbers = options.axisOptions.shortenYAxisNumbers || 0;\n\n\t\tthis.config.formatTooltipX = options.tooltipOptions.formatTooltipX;\n\t\tthis.config.formatTooltipY = options.tooltipOptions.formatTooltipY;\n\n\t\tthis.config.valuesOverPoints = options.valuesOverPoints;\n\t}\n\n\tprepareData(data=this.data) {\n\t\treturn dataPrep(data, this.type);\n\t}\n\n\tprepareFirstData(data=this.data) {\n\t\treturn zeroDataPrep(data);\n\t}\n\n\tcalc(onlyWidthChange = false) {\n\t\tthis.calcXPositions();\n\t\tif(!onlyWidthChange) {\n\t\t\tthis.calcYAxisParameters(this.getAllYValues(), this.type === 'line');\n\t\t}\n\t\tthis.makeDataByIndex();\n\t}\n\n\tcalcXPositions() {\n\t\tlet s = this.state;\n\t\tlet labels = this.data.labels;\n\t\ts.datasetLength = labels.length;\n\n\t\ts.unitWidth = this.width/(s.datasetLength);\n\t\t// Default, as per bar, and mixed. Only line will be a special case\n\t\ts.xOffset = s.unitWidth/2;\n\n\t\t// // For a pure Line Chart\n\t\t// s.unitWidth = this.width/(s.datasetLength - 1);\n\t\t// s.xOffset = 0;\n\n\t\ts.xAxis = {\n\t\t\tlabels: labels,\n\t\t\tpositions: labels.map((d, i) =>\n\t\t\t\tfloatTwo(s.xOffset + i * s.unitWidth)\n\t\t\t)\n\t\t};\n\t}\n\n\tcalcYAxisParameters(dataValues, withMinimum = 'false') {\n\t\tconst yPts = calcChartIntervals(dataValues, withMinimum);\n\t\tconst scaleMultiplier = this.height / getValueRange(yPts);\n\t\tconst intervalHeight = getIntervalSize(yPts) * scaleMultiplier;\n\t\tconst zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight);\n\n\t\tthis.state.yAxis = {\n\t\t\tlabels: yPts,\n\t\t\tpositions: yPts.map(d => zeroLine - d * scaleMultiplier),\n\t\t\tscaleMultiplier: scaleMultiplier,\n\t\t\tzeroLine: zeroLine,\n\t\t};\n\n\t\t// Dependent if above changes\n\t\tthis.calcDatasetPoints();\n\t\tthis.calcYExtremes();\n\t\tthis.calcYRegions();\n\t}\n\n\tcalcDatasetPoints() {\n\t\tlet s = this.state;\n\t\tlet scaleAll = values => values.map(val => scale(val, s.yAxis));\n\n\t\ts.datasets = this.data.datasets.map((d, i) => {\n\t\t\tlet values = d.values;\n\t\t\tlet cumulativeYs = d.cumulativeYs || [];\n\t\t\treturn {\n\t\t\t\tname: d.name && d.name.replace(/<|>|&/g, (char) => char == '&' ? '&' : char == '<' ? '<' : '>'),\n\t\t\t\tindex: i,\n\t\t\t\tchartType: d.chartType,\n\n\t\t\t\tvalues: values,\n\t\t\t\tyPositions: scaleAll(values),\n\n\t\t\t\tcumulativeYs: cumulativeYs,\n\t\t\t\tcumulativeYPos: scaleAll(cumulativeYs),\n\t\t\t};\n\t\t});\n\t}\n\n\tcalcYExtremes() {\n\t\tlet s = this.state;\n\t\tif(this.barOptions.stacked) {\n\t\t\ts.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos;\n\t\t\treturn;\n\t\t}\n\t\ts.yExtremes = new Array(s.datasetLength).fill(9999);\n\t\ts.datasets.map(d => {\n\t\t\td.yPositions.map((pos, j) => {\n\t\t\t\tif(pos < s.yExtremes[j]) {\n\t\t\t\t\ts.yExtremes[j] = pos;\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\t}\n\n\tcalcYRegions() {\n\t\tlet s = this.state;\n\t\tif(this.data.yMarkers) {\n\t\t\tthis.state.yMarkers = this.data.yMarkers.map(d => {\n\t\t\t\td.position = scale(d.value, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\t// if(!d.label.includes(':')) {\n\t\t\t\t// \td.label += ': ' + d.value;\n\t\t\t\t// }\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.state.yRegions = this.data.yRegions.map(d => {\n\t\t\t\td.startPos = scale(d.start, s.yAxis);\n\t\t\t\td.endPos = scale(d.end, s.yAxis);\n\t\t\t\tif(!d.options) d.options = {};\n\t\t\t\treturn d;\n\t\t\t});\n\t\t}\n\t}\n\n\tgetAllYValues() {\n\t\tlet key = 'values';\n\n\t\tif(this.barOptions.stacked) {\n\t\t\tkey = 'cumulativeYs';\n\t\t\tlet cumulative = new Array(this.state.datasetLength).fill(0);\n\t\t\tthis.data.datasets.map((d, i) => {\n\t\t\t\tlet values = this.data.datasets[i].values;\n\t\t\t\td[key] = cumulative = cumulative.map((c, i) => c + values[i]);\n\t\t\t});\n\t\t}\n\n\t\tlet allValueLists = this.data.datasets.map(d => d[key]);\n\t\tif(this.data.yMarkers) {\n\t\t\tallValueLists.push(this.data.yMarkers.map(d => d.value));\n\t\t}\n\t\tif(this.data.yRegions) {\n\t\t\tthis.data.yRegions.map(d => {\n\t\t\t\tallValueLists.push([d.end, d.start]);\n\t\t\t});\n\t\t}\n\n\t\treturn [].concat(...allValueLists);\n\t}\n\n\tsetupComponents() {\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'yAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.yAxisMode,\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tshortenNumbers: this.config.shortenYAxisNumbers\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'xAxis',\n\t\t\t\t{\n\t\t\t\t\tmode: this.config.xAxisMode,\n\t\t\t\t\theight: this.height,\n\t\t\t\t\t// pos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\ts.xAxis.calcLabels = getShortenedLabels(this.width,\n\t\t\t\t\t\ts.xAxis.labels, this.config.xIsSeries);\n\n\t\t\t\t\treturn s.xAxis;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\n\t\t\t[\n\t\t\t\t'yRegions',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yRegions;\n\t\t\t\t}.bind(this)\n\t\t\t],\n\t\t];\n\n\t\tlet barDatasets = this.state.datasets.filter(d => d.chartType === 'bar');\n\t\tlet lineDatasets = this.state.datasets.filter(d => d.chartType === 'line');\n\n\t\tlet barsConfigs = barDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'barGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tstacked: this.barOptions.stacked,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t\tminHeight: this.height * MIN_BAR_PERCENT_HEIGHT,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet stacked = this.barOptions.stacked;\n\n\t\t\t\t\tlet spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO;\n\t\t\t\t\tlet barsWidth = s.unitWidth * (1 - spaceRatio);\n\t\t\t\t\tlet barWidth = barsWidth/(stacked ? 1 : barDatasets.length);\n\n\t\t\t\t\tlet xPositions = s.xAxis.positions.map(x => x - barsWidth/2);\n\t\t\t\t\tif(!stacked) {\n\t\t\t\t\t\txPositions = xPositions.map(p => p + barWidth * index);\n\t\t\t\t\t}\n\n\t\t\t\t\tlet labels = new Array(s.datasetLength).fill('');\n\t\t\t\t\tif(this.config.valuesOverPoints) {\n\t\t\t\t\t\tif(stacked && d.index === s.datasets.length - 1) {\n\t\t\t\t\t\t\tlabels = d.cumulativeYs;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tlabels = d.values;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tlet offsets = new Array(s.datasetLength).fill(0);\n\t\t\t\t\tif(stacked) {\n\t\t\t\t\t\toffsets = d.yPositions.map((y, j) => y - d.cumulativeYPos[j]);\n\t\t\t\t\t}\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: xPositions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\t\t\t\t\t\toffsets: offsets,\n\t\t\t\t\t\t// values: d.values,\n\t\t\t\t\t\tlabels: labels,\n\n\t\t\t\t\t\tzeroLine: s.yAxis.zeroLine,\n\t\t\t\t\t\tbarsWidth: barsWidth,\n\t\t\t\t\t\tbarWidth: barWidth,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet lineConfigs = lineDatasets.map(d => {\n\t\t\tlet index = d.index;\n\t\t\treturn [\n\t\t\t\t'lineGraph' + '-' + d.index,\n\t\t\t\t{\n\t\t\t\t\tindex: index,\n\t\t\t\t\tcolor: this.colors[index],\n\t\t\t\t\tsvgDefs: this.svgDefs,\n\t\t\t\t\theatline: this.lineOptions.heatline,\n\t\t\t\t\tregionFill: this.lineOptions.regionFill,\n\t\t\t\t\tspline: this.lineOptions.spline,\n\t\t\t\t\thideDots: this.lineOptions.hideDots,\n\t\t\t\t\thideLine: this.lineOptions.hideLine,\n\n\t\t\t\t\t// same for all datasets\n\t\t\t\t\tvaluesOverPoints: this.config.valuesOverPoints,\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\tlet s = this.state;\n\t\t\t\t\tlet d = s.datasets[index];\n\t\t\t\t\tlet minLine = s.yAxis.positions[0] < s.yAxis.zeroLine\n\t\t\t\t\t\t? s.yAxis.positions[0] : s.yAxis.zeroLine;\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\txPositions: s.xAxis.positions,\n\t\t\t\t\t\tyPositions: d.yPositions,\n\n\t\t\t\t\t\tvalues: d.values,\n\n\t\t\t\t\t\tzeroLine: minLine,\n\t\t\t\t\t\tradius: this.lineOptions.dotSize || LINE_CHART_DOT_SIZE,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t];\n\t\t});\n\n\t\tlet markerConfigs = [\n\t\t\t[\n\t\t\t\t'yMarkers',\n\t\t\t\t{\n\t\t\t\t\twidth: this.width,\n\t\t\t\t\tpos: 'right'\n\t\t\t\t},\n\t\t\t\tfunction() {\n\t\t\t\t\treturn this.state.yMarkers;\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tcomponentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs);\n\n\t\tlet optionals = ['yMarkers', 'yRegions'];\n\t\tthis.dataUnitComponents = [];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.filter(args => !optionals.includes(args[0]) || this.state[args[0]])\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\tif(args[0].includes('lineGraph') || args[0].includes('barGraph')) {\n\t\t\t\t\tthis.dataUnitComponents.push(component);\n\t\t\t\t}\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tmakeDataByIndex() {\n\t\tthis.dataByIndex = {};\n\n\t\tlet s = this.state;\n\t\tlet formatX = this.config.formatTooltipX;\n\t\tlet formatY = this.config.formatTooltipY;\n\t\tlet titles = s.xAxis.labels;\n\n\t\ttitles.map((label, index) => {\n\t\t\tlet values = this.state.datasets.map((set, i) => {\n\t\t\t\tlet value = set.values[index];\n\t\t\t\treturn {\n\t\t\t\t\ttitle: set.name,\n\t\t\t\t\tvalue: value,\n\t\t\t\t\tyPos: set.yPositions[index],\n\t\t\t\t\tcolor: this.colors[i],\n\t\t\t\t\tformatted: formatY ? formatY(value) : value,\n\t\t\t\t};\n\t\t\t});\n\n\t\t\tthis.dataByIndex[index] = {\n\t\t\t\tlabel: label,\n\t\t\t\tformattedLabel: formatX ? formatX(label) : label,\n\t\t\t\txPos: s.xAxis.positions[index],\n\t\t\t\tvalues: values,\n\t\t\t\tyExtreme: s.yExtremes[index],\n\t\t\t};\n\t\t});\n\t}\n\n\tbindTooltip() {\n\t\t// NOTE: could be in tooltip itself, as it is a given functionality for its parent\n\t\tthis.container.addEventListener('mousemove', (e) => {\n\t\t\tlet m = this.measures;\n\t\t\tlet o = getOffset(this.container);\n\t\t\tlet relX = e.pageX - o.left - getLeftOffset(m);\n\t\t\tlet relY = e.pageY - o.top;\n\n\t\t\tif(relY < this.height + getTopOffset(m)\n\t\t\t\t&& relY > getTopOffset(m)) {\n\t\t\t\tthis.mapTooltipXPosition(relX);\n\t\t\t} else {\n\t\t\t\tthis.tip.hideTip();\n\t\t\t}\n\t\t});\n\t}\n\n\tmapTooltipXPosition(relX) {\n\t\tlet s = this.state;\n\t\tif(!s.yExtremes) return;\n\n\t\tlet index = getClosestInArray(relX, s.xAxis.positions, true);\n\t\tif (index >= 0) {\n\t\t\tlet dbi = this.dataByIndex[index];\n\n\t\t\tthis.tip.setValues(\n\t\t\t\tdbi.xPos + this.tip.offset.x,\n\t\t\t\tdbi.yExtreme + this.tip.offset.y,\n\t\t\t\t{name: dbi.formattedLabel, value: ''},\n\t\t\t\tdbi.values,\n\t\t\t\tindex\n\t\t\t);\n\n\t\t\tthis.tip.showTip();\n\t\t}\n\t}\n\n\trenderLegend() {\n\t\tlet s = this.data;\n\t\tif(s.datasets.length > 1) {\n\t\t\tthis.legendArea.textContent = '';\n\t\t\ts.datasets.map((d, i) => {\n\t\t\t\tlet barWidth = AXIS_LEGEND_BAR_SIZE;\n\t\t\t\t// let rightEndPoint = this.baseWidth - this.measures.margins.left - this.measures.margins.right;\n\t\t\t\t// let multiplier = s.datasets.length - i;\n\t\t\t\tlet rect = legendBar(\n\t\t\t\t\t// rightEndPoint - multiplier * barWidth,\t// To right align\n\t\t\t\t\tbarWidth * i,\n\t\t\t\t\t'0',\n\t\t\t\t\tbarWidth,\n\t\t\t\t\tthis.colors[i],\n\t\t\t\t\td.name,\n\t\t\t\t\tthis.config.truncateLegends);\n\t\t\t\tthis.legendArea.appendChild(rect);\n\t\t\t});\n\t\t}\n\t}\n\n\n\n\t// Overlay\n\tmakeOverlay() {\n\t\tif(this.init) {\n\t\t\tthis.init = 0;\n\t\t\treturn;\n\t\t}\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\n\t\tthis.overlayGuides = this.dataUnitComponents.map(c => {\n\t\t\treturn {\n\t\t\t\ttype: c.unitType,\n\t\t\t\toverlay: undefined,\n\t\t\t\tunits: c.units,\n\t\t\t};\n\t\t});\n\n\t\tif(this.state.currentIndex === undefined) {\n\t\t\tthis.state.currentIndex = this.state.datasetLength - 1;\n\t\t}\n\n\t\t// Render overlays\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\n\t\t\td.overlay = makeOverlay[d.type](currentUnit);\n\t\t\tthis.drawArea.appendChild(d.overlay);\n\t\t});\n\t}\n\n\tupdateOverlayGuides() {\n\t\tif(this.overlayGuides) {\n\t\t\tthis.overlayGuides.forEach(g => {\n\t\t\t\tlet o = g.overlay;\n\t\t\t\to.parentNode.removeChild(o);\n\t\t\t});\n\t\t}\n\t}\n\n\tbindOverlay() {\n\t\tthis.parent.addEventListener('data-select', () => {\n\t\t\tthis.updateOverlay();\n\t\t});\n\t}\n\n\tbindUnits() {\n\t\tthis.dataUnitComponents.map(c => {\n\t\t\tc.units.map(unit => {\n\t\t\t\tunit.addEventListener('click', () => {\n\t\t\t\t\tlet index = unit.getAttribute('data-point-index');\n\t\t\t\t\tthis.setCurrentDataPoint(index);\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\t// Note: Doesn't work as tooltip is absolutely positioned\n\t\tthis.tip.container.addEventListener('click', () => {\n\t\t\tlet index = this.tip.container.getAttribute('data-point-index');\n\t\t\tthis.setCurrentDataPoint(index);\n\t\t});\n\t}\n\n\tupdateOverlay() {\n\t\tthis.overlayGuides.map(d => {\n\t\t\tlet currentUnit = d.units[this.state.currentIndex];\n\t\t\tupdateOverlay[d.type](currentUnit, d.overlay);\n\t\t});\n\t}\n\n\tonLeftArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex - 1);\n\t}\n\n\tonRightArrow() {\n\t\tthis.setCurrentDataPoint(this.state.currentIndex + 1);\n\t}\n\n\tgetDataPoint(index=this.state.currentIndex) {\n\t\tlet s = this.state;\n\t\tlet data_point = {\n\t\t\tindex: index,\n\t\t\tlabel: s.xAxis.labels[index],\n\t\t\tvalues: s.datasets.map(d => d.values[index])\n\t\t};\n\t\treturn data_point;\n\t}\n\n\tsetCurrentDataPoint(index) {\n\t\tlet s = this.state;\n\t\tindex = parseInt(index);\n\t\tif(index < 0) index = 0;\n\t\tif(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1;\n\t\tif(index === s.currentIndex) return;\n\t\ts.currentIndex = index;\n\t\tfire(this.parent, \"data-select\", this.getDataPoint());\n\t}\n\n\n\n\t// API\n\taddDataPoint(label, datasetValues, index=this.state.datasetLength) {\n\t\tsuper.addDataPoint(label, datasetValues, index);\n\t\tthis.data.labels.splice(index, 0, label);\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\td.values.splice(index, 0, datasetValues[i]);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tremoveDataPoint(index = this.state.datasetLength-1) {\n\t\tif (this.data.labels.length <= 1) {\n\t\t\treturn;\n\t\t}\n\t\tsuper.removeDataPoint(index);\n\t\tthis.data.labels.splice(index, 1);\n\t\tthis.data.datasets.map(d => {\n\t\t\td.values.splice(index, 1);\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\tupdateDataset(datasetValues, index=0) {\n\t\tthis.data.datasets[index].values = datasetValues;\n\t\tthis.update(this.data);\n\t}\n\t// addDataset(dataset, index) {}\n\t// removeDataset(index = 0) {}\n\n\tupdateDatasets(datasets) {\n\t\tthis.data.datasets.map((d, i) => {\n\t\t\tif(datasets[i]) {\n\t\t\t\td.values = datasets[i];\n\t\t\t}\n\t\t});\n\t\tthis.update(this.data);\n\t}\n\n\t// updateDataPoint(dataPoint, index = 0) {}\n\t// addDataPoint(dataPoint, index = 0) {}\n\t// removeDataPoint(index = 0) {}\n}\n","import AggregationChart from './AggregationChart';\nimport { getComponent } from '../objects/ChartComponents';\nimport { getOffset } from '../utils/dom';\nimport { getPositionByAngle } from '../utils/helpers';\nimport { makeArcStrokePathStr, makeStrokeCircleStr } from '../utils/draw';\nimport { lightenDarkenColor } from '../utils/colors';\nimport { transform } from '../utils/animation';\nimport { FULL_ANGLE } from '../utils/constants';\n\nexport default class DonutChart extends AggregationChart {\n\tconstructor(parent, args) {\n\t\tsuper(parent, args);\n\t\tthis.type = 'donut';\n\t\tthis.initTimeout = 0;\n\t\tthis.init = 1;\n\n\t\tthis.setup();\n\t}\n\n\tconfigure(args) {\n\t\tsuper.configure(args);\n\t\tthis.mouseMove = this.mouseMove.bind(this);\n\t\tthis.mouseLeave = this.mouseLeave.bind(this);\n\n\t\tthis.hoverRadio = args.hoverRadio || 0.1;\n\t\tthis.config.startAngle = args.startAngle || 0;\n\n\t\tthis.clockWise = args.clockWise || false;\n\t\tthis.strokeWidth = args.strokeWidth || 30;\n\t}\n\n\tcalc() {\n\t\tsuper.calc();\n\t\tlet s = this.state;\n\t\tthis.radius =\n\t\t\tthis.height > this.width\n\t\t\t\t? this.center.x - this.strokeWidth / 2\n\t\t\t\t: this.center.y - this.strokeWidth / 2;\n\n\t\tconst { radius, clockWise } = this;\n\n\t\tconst prevSlicesProperties = s.slicesProperties || [];\n\t\ts.sliceStrings = [];\n\t\ts.slicesProperties = [];\n\t\tlet curAngle = 180 - this.config.startAngle;\n\n\t\ts.sliceTotals.map((total, i) => {\n\t\t\tconst startAngle = curAngle;\n\t\t\tconst originDiffAngle = (total / s.grandTotal) * FULL_ANGLE;\n\t\t\tconst largeArc = originDiffAngle > 180 ? 1: 0;\n\t\t\tconst diffAngle = clockWise ? -originDiffAngle : originDiffAngle;\n\t\t\tconst endAngle = curAngle = curAngle + diffAngle;\n\t\t\tconst startPosition = getPositionByAngle(startAngle, radius);\n\t\t\tconst endPosition = getPositionByAngle(endAngle, radius);\n\n\t\t\tconst prevProperty = this.init && prevSlicesProperties[i];\n\n\t\t\tlet curStart,curEnd;\n\t\t\tif(this.init) {\n\t\t\t\tcurStart = prevProperty ? prevProperty.startPosition : startPosition;\n\t\t\t\tcurEnd = prevProperty ? prevProperty.endPosition : startPosition;\n\t\t\t} else {\n\t\t\t\tcurStart = startPosition;\n\t\t\t\tcurEnd = endPosition;\n\t\t\t}\n\t\t\tconst curPath =\n\t\t\t\toriginDiffAngle === 360\n\t\t\t\t\t? makeStrokeCircleStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc)\n\t\t\t\t\t: makeArcStrokePathStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc);\n\n\t\t\ts.sliceStrings.push(curPath);\n\t\t\ts.slicesProperties.push({\n\t\t\t\tstartPosition,\n\t\t\t\tendPosition,\n\t\t\t\tvalue: total,\n\t\t\t\ttotal: s.grandTotal,\n\t\t\t\tstartAngle,\n\t\t\t\tendAngle,\n\t\t\t\tangle: diffAngle\n\t\t\t});\n\n\t\t});\n\t\tthis.init = 0;\n\t}\n\n\tsetupComponents() {\n\t\tlet s = this.state;\n\n\t\tlet componentConfigs = [\n\t\t\t[\n\t\t\t\t'donutSlices',\n\t\t\t\t{ },\n\t\t\t\tfunction() {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tsliceStrings: s.sliceStrings,\n\t\t\t\t\t\tcolors: this.colors,\n\t\t\t\t\t\tstrokeWidth: this.strokeWidth,\n\t\t\t\t\t};\n\t\t\t\t}.bind(this)\n\t\t\t]\n\t\t];\n\n\t\tthis.components = new Map(componentConfigs\n\t\t\t.map(args => {\n\t\t\t\tlet component = getComponent(...args);\n\t\t\t\treturn [args[0], component];\n\t\t\t}));\n\t}\n\n\tcalTranslateByAngle(property){\n\t\tconst{ radius, hoverRadio } = this;\n\t\tconst position = getPositionByAngle(property.startAngle+(property.angle / 2),radius);\n\t\treturn `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`;\n\t}\n\n\thoverSlice(path,i,flag,e){\n\t\tif(!path) return;\n\t\tconst color = this.colors[i];\n\t\tif(flag) {\n\t\t\ttransform(path, this.calTranslateByAngle(this.state.slicesProperties[i]));\n\t\t\tpath.style.stroke = lightenDarkenColor(color, 50);\n\t\t\tlet g_off = getOffset(this.svg);\n\t\t\tlet x = e.pageX - g_off.left + 10;\n\t\t\tlet y = e.pageY - g_off.top - 10;\n\t\t\tlet title = (this.formatted_labels && this.formatted_labels.length > 0\n\t\t\t\t? this.formatted_labels[i] : this.state.labels[i]) + ': ';\n\t\t\tlet percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1);\n\t\t\tthis.tip.setValues(x, y, {name: title, value: percent + \"%\"});\n\t\t\tthis.tip.showTip();\n\t\t} else {\n\t\t\ttransform(path,'translate3d(0,0,0)');\n\t\t\tthis.tip.hideTip();\n\t\t\tpath.style.stroke = color;\n\t\t}\n\t}\n\n\tbindTooltip() {\n\t\tthis.container.addEventListener('mousemove', this.mouseMove);\n\t\tthis.container.addEventListener('mouseleave', this.mouseLeave);\n\t}\n\n\tmouseMove(e){\n\t\tconst target = e.target;\n\t\tlet slices = this.components.get('donutSlices').store;\n\t\tlet prevIndex = this.curActiveSliceIndex;\n\t\tlet prevAcitve = this.curActiveSlice;\n\t\tif(slices.includes(target)) {\n\t\t\tlet i = slices.indexOf(target);\n\t\t\tthis.hoverSlice(prevAcitve, prevIndex,false);\n\t\t\tthis.curActiveSlice = target;\n\t\t\tthis.curActiveSliceIndex = i;\n\t\t\tthis.hoverSlice(target, i, true, e);\n\t\t} else {\n\t\t\tthis.mouseLeave();\n\t\t}\n\t}\n\n\tmouseLeave(){\n\t\tthis.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false);\n\t}\n}\n","import * as Charts from './chart';\n\nlet frappe = { };\n\nfrappe.NAME = 'Frappe Charts';\nfrappe.VERSION = '1.6.2';\n\nfrappe = Object.assign({ }, frappe, Charts);\n\nexport default frappe;"],"names":["expr","con","document","querySelector","getOffset","element","rect","getBoundingClientRect","top","documentElement","scrollTop","body","left","scrollLeft","isHidden","el","offsetParent","isElementInViewport","bottom","window","innerHeight","clientHeight","right","innerWidth","clientWidth","getElementContentWidth","styles","getComputedStyle","padding","parseFloat","paddingLeft","paddingRight","fire","target","type","properties","evt","createEvent","initEvent","j","dispatchEvent","getTopOffset","m","titleHeight","margins","paddings","getLeftOffset","getExtraHeight","legendHeight","getExtraWidth","floatTwo","d","toFixed","fillArray","array","count","start","length","fillerArray","Array","Math","abs","fill","concat","getStringWidth","string","charWidth","getPositionByAngle","angle","radius","sin","ANGLE_RATIO","cos","isValidNumber","candidate","nonNegative","Number","isNaN","undefined","isFinite","round","deepClone","cloned","value","key","Date","getTime","isArray","getBarHeightAndYAttr","yTop","zeroLine","height","y","equilizeNoOfElements","array1","array2","extraCount","truncateString","txt","len","slice","shortenLargeNumber","label","number","p","floor","log10","l","shortened","pow","getSplineCurvePointsStr","xList","yList","points","i","push","line","pointA","pointB","lengthX","lengthY","sqrt","atan2","controlPoint","current","previous","next","reverse","o","PI","command","reduce","acc","point","a","cps","cpe","limitColor","r","lightenDarkenColor","color","amt","col","getColor","usePound","num","parseInt","b","g","toString","isValidColor","RGB_RE","test","$","createSVG","tag","createElementNS","val","appendChild","ref","parentNode","insertBefore","keys","map","style","prop","setAttribute","renderVerticalGradient","svgDefElem","gradientId","setGradientStop","gradElem","offset","opacity","makeSVGContainer","parent","className","width","makeSVGDefs","svgContainer","makeSVGGroup","transform","args","inside","makePath","pathStr","makeArcPathStr","startPosition","endPosition","center","clockWise","largeArc","arcStartX","x","arcStartY","arcEndX","arcEndY","makeCircleStr","midArc","makeArcStrokePathStr","makeStrokeCircleStr","makeGradient","lighter","gradientDef","opacities","percentageBar","depth","PERCENTAGE_BAR_DEFAULT_DEPTH","heatSquare","size","data","legendBar","LABEL_MAX_CHARS","text","FONT_SIZE","FONT_FILL","group","legendDot","makeText","content","options","fontSize","dy","textAnchor","makeVertLine","y1","y2","stroke","BASE_LINE_COLOR","LABEL_MARGIN","makeHoriLine","x1","x2","lineType","shortenNumbers","yLine","pos","mode","AXIS_TICK_LENGTH","xLine","yMarker","labelPos","labelSvg","yRegion","region","datasetBar","index","meta","minHeight","datasetDot","dot","getPaths","pointsStr","join","spline","path","heatline","gradient_id","svgDefs","paths","regionFill","gradient_id_region","translate","unit","oldCoord","newCoord","duration","old","STD_EASING","translateVertLine","newX","oldX","MARKER_LINE_ANIM_DUR","translateHoriLine","newY","oldY","animateRegion","rectGroup","newY1","newY2","oldY2","newHeight","childNodes","stroke-dasharray","getAttribute","animateBar","bar","nodeName","UNIT_ANIM_DUR","split","animateDot","cx","cy","animatePath","newXList","newYList","pathComponents","animPath","PATH_ANIM_DUR","regStartPt","regEndPt","animRegion","animatePathStr","oldPath","animateSVGElement","props","dur","easingType","oldValues","animElement","cloneNode","newElement","attributeName","animateElement","currentValue","animAttr","EASING","webkitTransform","msTransform","mozTransform","oTransform","animateSVG","elements","newElements","animElements","replaceChild","animSvg","runSMILAnimation","svgElement","elementsToAnimate","animSvgElement","removeChild","REPLACE_ALL_NEW_DUR","downloadFile","filename","createElement","blob","Blob","url","URL","createObjectURL","href","download","click","revokeObjectURL","prepareForExport","svg","clone","classList","add","styleEl","create","CSSTEXT","firstChild","container","innerHTML","treatAsUtc","date","result","setMinutes","getMinutes","getTimezoneOffset","getYyyyMmDd","dd","getDate","mm","getMonth","getFullYear","getWeeksBetween","startDate","endDate","weekStartDate","setDayToSunday","ceil","getDaysBetween","NO_OF_DAYS_IN_WEEK","millisecondsPerDay","SEC_IN_DAY","NO_OF_MILLIS","areInSameMonth","getMonthName","short","monthName","MONTH_NAMES","getLastDateInMonth","month","year","newDate","day","getDay","addDays","numberOfDays","setDate","getComponent","name","constants","getData","Object","componentConfigs","filter","includes","k","config","assign","ChartComponent","normalize","mantissa","exponent","sig","exp","getChartRangeIntervals","max","min","upperBound","lowerBound","range","noOfParts","partSize","intervals","getChartIntervals","maxValue","minValue","normalMaxValue","normalMinValue","calcChartIntervals","values","getPositiveFirstIntervals","absMinValue","intervalSize","unshift","withMinimum","pseudoMaxValue","pseudoMinValue","getZeroIndex","yPts","interval","getIntervalSize","indexOf","orderedArray","getValueRange","scale","yAxis","scaleMultiplier","getClosestInArray","goal","arr","closest","prev","curr","calcDistribution","distributionSize","dataMaxValue","distributionStep","distribution","checkpoint","getMaxCheckpoint","dataPrep","labels","datasetLength","datasets","zeroArray","vals","chartType","AXIS_DATASET_CHART_TYPES","yRegions","end","zeroDataPrep","realData","zeroData","yMarkers","getShortenedLabels","chartWidth","isSeries","allowedSpace","allowedLetters","DEFAULT_CHAR_WIDTH","seriesMultiple","maxLabelLength","getChartByType","AxisChart","chartTypes","error","css","insertAt","head","getElementsByTagName","styleSheet","cssText","createTextNode","BASE_MEASURES","INIT_CHART_UPDATE_TIMEOUT","DEFAULT_CHART_COLORS","DEFAULT_COLORS","SvgTip","colors","titleName","titleValue","listValues","titleValueFirst","setup","makeTooltip","calcPosition","this","hideTip","title","dataPointList","addEventListener","set","_this2","formatted","li","offsetWidth","offsetHeight","maxLeft","pointer","pointerOffset","valueFirst","refresh","PRESET_COLOR_MAP","exec","c","ch","makeOverlay","transformValue","overlay","updateOverlay","attributes","attr","specified","nodeValue","BaseChart","HTMLElement","Error","rawChartArgs","prepareData","prepareFirstData","validateColors","isNavigable","animate","truncateLegends","measures","JSON","parse","stringify","setMeasures","showLegend","argHeight","baseHeight","state","initTimeout","overlays","configure","validColors","forEach","warn","boundDrawFn","_this","draw","ResizeObserver","resizeObserver","observe","disconnect","removeEventListener","makeContainer","updateWidth","independentWidth","tip","bindTooltip","onlyWidthChange","init","calc","makeChartArea","setupComponents","components","drawArea","render","update","renderLegend","setupNavigation","baseWidth","titleEL","titleFontSize","legendArea","updateTipOffset","Map","make","updateNav","bindUnits","bindOverlay","keyActions","onEnterKey","bind","onLeftArrow","onUpArrow","onRightArrow","onDownArrow","e","_this4","event","keyCode","chartSvg","AggregationChart","formatTooltipY","tooltipOptions","maxSlices","maxLegendPoints","s","sliceTotals","allTotals","total","totals","sort","sumOfRemaining","grandTotal","textContent","legendTotals","barWidth","divisor","_this3","DAY_NAMES_SHORT","layerClass","layerTransform","makeElements","animateElements","store","layer","oldData","sliceStrings","strokeWidth","transition","newData","xPositions","widths","barHeight","barDepth","positions","position","newPos","newLabels","oldPos","oldLabels","calcLabels","_this5","newOptions","startPos","endPos","_this6","newStarts","oldStarts","colWidth","rowHeight","squareSize","xTranslate","serializedSubDomains","cols","week","weekNo","toUpperCase","yyyyMmDd","dataValue","square","unitType","units","yPositions","offsets","barsWidth","newXPos","newYPos","newOffsets","oldXPos","oldYPos","oldOffsets","hideLine","hideDots","valuesOverPoints","newValues","PercentageChart","barOptions","component","xPos","bars","get","gOff","pOff","formattedLabels","fraction","setValues","showTip","PieChart","mouseMove","mouseLeave","hoverRadio","startAngle","prevSlicesProperties","slicesProperties","curAngle","originDiffAngle","diffAngle","endAngle","prevProperty","curStart","curEnd","curPath","property","flag","calTranslateByAngle","g_off","pageX","pageY","formatted_labels","percent","slices","prevIndex","curActiveSliceIndex","prevAcitve","curActiveSlice","hoverSlice","Heatmap","countLabel","validStarts","startSubDomain","startSubDomainIndex","discreteDomains","ROW_HEIGHT","HEATMAP_SQUARE_SIZE","spacing","noOfWeeks","setFullYear","dataPoints","timestampSec","firstWeekStart","domainConfigs","getDomains","lessCol","dayName","dayText","daySquares","comp","daySquare","dateParts","lessText","COL_WIDTH","moreText","HEATMAP_DISTRIBUTION_SIZE","startMonth","startYear","noOfMonths","startOfMonth","getDomainConfig","startOfWeek","domainConfig","noOfMonthWeeks","getCol","empty","currentDate","currentDateWithinData","getSubDomainConfig","lineOptions","axisOptions","xAxisMode","yAxisMode","xIsSeries","shortenYAxisNumbers","formatTooltipX","calcXPositions","calcYAxisParameters","getAllYValues","makeDataByIndex","unitWidth","xOffset","xAxis","dataValues","intervalHeight","calcDatasetPoints","calcYExtremes","calcYRegions","scaleAll","cumulativeYs","replace","char","stacked","yExtremes","cumulativeYPos","cumulative","allValueLists","barDatasets","lineDatasets","barsConfigs","spaceRatio","lineConfigs","minLine","dotSize","markerConfigs","optionals","dataUnitComponents","dataByIndex","formatX","formatY","relX","relY","mapTooltipXPosition","dbi","yExtreme","formattedLabel","overlayGuides","currentIndex","currentUnit","_this7","setCurrentDataPoint","_this9","_this10","getDataPoint","datasetValues","splice","DonutChart","Chart","frappe","NAME","VERSION","Charts"],"mappings":"wMACwB,gBAATA,IAAoBC,GAAOC,UAAUC,cAAcH,GAAQA,GAAQ,KA4ClF,QAAgBI,GAAUC,MACrBC,GAAOD,EAAQE,mCAKbD,EAAKE,KAAON,SAASO,gBAAgBC,WAAaR,SAASS,KAAKD,gBAC/DJ,EAAKM,MAAQV,SAASO,gBAAgBI,YAAcX,SAASS,KAAKE,aAO1E,QAAgBC,GAASC,SACI,QAApBA,EAAGC,aAGZ,QAAgBC,GAAoBF,MAE/BT,GAAOS,EAAGR,8BAGbD,GAAKE,KAAO,GACNF,EAAKM,MAAQ,GACbN,EAAKY,SAAWC,OAAOC,aAAelB,SAASO,gBAAgBY,iBAC1DC,QAAUH,OAAOI,YAAcrB,SAASO,gBAAgBe,aAIrE,QAAgBC,GAAuBpB,MAClCqB,GAASP,OAAOQ,iBAAiBtB,GACjCuB,EAAUC,WAAWH,EAAOI,aAC/BD,WAAWH,EAAOK,oBAEZ1B,GAAQmB,YAAcI,EA2B9B,QAAgBI,GAAKC,EAAQC,EAAMC,MAC9BC,GAAMlC,SAASmC,YAAY,gBAE3BC,UAAUJ,GAAM,GAAM,OAErB,GAAIK,KAAKJ,KACTI,GAAKJ,EAAWI,SAGdN,GAAOO,cAAcJ,GC7E7B,QAAgBK,GAAaC,SACrBA,GAAEC,YAAcD,EAAEE,QAAQpC,IAAMkC,EAAEG,SAASrC,IAGnD,QAAgBsC,GAAcJ,SACtBA,GAAEE,QAAQhC,KAAO8B,EAAEG,SAASjC,KAGpC,QAAgBmC,GAAeL,SACPA,GAAEE,QAAQpC,IAAMkC,EAAEE,QAAQ1B,OAC9CwB,EAAEG,SAASrC,IAAMkC,EAAEG,SAAS3B,OAC5BwB,EAAEC,YAAcD,EAAEM,aAItB,QAAgBC,GAAcP,SACPA,GAAEE,QAAQhC,KAAO8B,EAAEE,QAAQtB,MAC9CoB,EAAEG,SAASjC,KAAO8B,EAAEG,SAASvB,MClDjC,QAAgB4B,GAASC,SACjBtB,YAAWsB,EAAEC,QAAQ,IAyC7B,QAAgBC,GAAUC,EAAOC,EAAOlD,MAASmD,0DAC5CnD,OACOmD,EAAQF,EAAM,GAAKA,EAAMA,EAAMG,OAAS,OAE/CC,GAAc,GAAIC,OAAMC,KAAKC,IAAIN,IAAQO,KAAKzD,YAC1CmD,EAAQE,EAAYK,OAAOT,GAASA,EAAMS,OAAOL,GAS1D,QAAgBM,GAAeC,EAAQC,UAC9BD,EAAO,IAAIR,OAASS,EAyB7B,QAAgBC,GAAmBC,EAAOC,YAErCT,KAAKU,IAAIF,EAAQG,IAAeF,IAChCT,KAAKY,IAAIJ,EAAQG,IAAeF,GASrC,QAAgBI,GAAcC,MAAWC,kEACpCC,OAAOC,MAAMH,SACMI,KAAdJ,MACCE,OAAOG,SAASL,MACjBC,GAAeD,EAAY,KAQrC,QAAgBM,GAAM7B,SAGdyB,QAAOhB,KAAKoB,MAAM7B,EAAI,MAAQ,OAOrC,QAAgB8B,GAAUP,MACtBQ,UAAQC,SAAOC,YAEfV,YAAqBW,YAChB,IAAIA,MAAKX,EAAUY,cAGH,qBAAdZ,iBAAAA,KAAwC,OAAdA,QAC5BA,KAGAf,MAAM4B,QAAQb,aAElBU,IAAOV,KACFA,EAAUU,KAEXA,GAAOH,EAAUE,SAGnBD,GC3ID,QAASM,GAAqBC,EAAMC,MACtCC,UAAQC,eACRH,IAAQC,KACFA,EAAWD,IAChBA,MAEKA,EAAOC,IACZA,IAGGC,EAAQC,GAGjB,QAAgBC,GAAqBC,EAAQC,MAC5CC,0DAAaD,EAAOtC,OAASqC,EAAOrC,aAGjCuC,GAAa,IACN3C,EAAUyC,EAAQE,KAElB3C,EAAU0C,EAAQC,IAEpBF,EAAQC,GAGjB,QAAgBE,GAAeC,EAAKC,MAC9BD,QAGDA,GAAIzC,OAAS0C,EACTD,EAAIE,MAAM,EAAGD,EAAI,GAAK,MAEtBD,EAIT,QAAgBG,GAAmBC,MAC9BC,aACiB,gBAAVD,GAAoBC,EAASD,MACnC,IAAqB,gBAAVA,OACN1B,OAAO0B,GACZ1B,OAAOC,MAAM0B,IAAS,MAAOD,MAI9BE,GAAI5C,KAAK6C,MAAM7C,KAAK8C,MAAM9C,KAAKC,IAAI0C,QACnCC,GAAK,EAAG,MAAOD,MACfI,GAAI/C,KAAK6C,MAAMD,EAAI,GACnBI,EAAahD,KAAKiD,IAAI,GAAIL,EAAQ,EAAJG,KAAWJ,EAAS3C,KAAKiD,IAAI,GAAIL,IAAIpD,QAAQ,SAGxEQ,MAAKoB,MAAgB,IAAV4B,GAAe,IAAM,KAAO,GAAI,IAAK,IAAK,IAAK,KAAKD,GAIvE,QAAgBG,GAAwBC,EAAOC,OAG1C,GADAC,MACIC,EAAE,EAAEA,EAAEH,EAAMtD,OAAOyD,MACnBC,MAAMJ,EAAMG,GAAIF,EAAME,QAI1BE,GAAO,SAACC,EAAQC,MACfC,GAAUD,EAAO,GAAKD,EAAO,GAC7BG,EAAUF,EAAO,GAAKD,EAAO,iBAExBzD,KAAK6D,KAAK7D,KAAKiD,IAAIU,EAAS,GAAK3D,KAAKiD,IAAIW,EAAS,UACpD5D,KAAK8D,MAAMF,EAASD,KAIzBI,EAAe,SAACC,EAASC,EAAUC,EAAMC,MAGxCC,GAAIZ,EAFAS,GAAYD,EACZE,GAAQF,GAEZxD,EAAQ4D,EAAE5D,OAAS2D,EAAUnE,KAAKqE,GAAK,GACvCxE,EAfW,GAeFuE,EAAEvE,cACPmE,EAAQ,GAAKhE,KAAKY,IAAIJ,GAASX,EAC/BmE,EAAQ,GAAKhE,KAAKU,IAAIF,GAASX,UAUzB,UAACwD,EAAQiB,SAChBjB,GAAOkB,OAAO,SAACC,EAAKC,EAAOnB,EAAGoB,SAAY,KAANpB,EACrCmB,EAAM,OAAMA,EAAM,GAClBD,MAAOF,EAAQG,EAAOnB,EAAGoB,IAAM,KAGtBrB,EAZI,SAACoB,EAAOnB,EAAGoB,MAC1BC,GAAMZ,EAAaW,EAAEpB,EAAI,GAAIoB,EAAEpB,EAAI,GAAImB,GACvCG,EAAMb,EAAaU,EAAOC,EAAEpB,EAAI,GAAIoB,EAAEpB,EAAI,IAAI,cACtCqB,EAAI,OAAMA,EAAI,OAAMC,EAAI,OAAMA,EAAI,OAAMH,EAAM,OAAMA,EAAM,KCvExE,QAASI,GAAWC,SACfA,GAAI,IAAY,IACXA,EAAI,EAAU,EAChBA,EAGR,QAAgBC,GAAmBC,EAAOC,MACrCC,GAAMC,GAASH,GACfI,GAAW,CACD,MAAVF,EAAI,OACDA,EAAI1C,MAAM,MACL,MAER6C,GAAMC,SAASJ,EAAI,IACnBJ,EAAID,GAAYQ,GAAO,IAAMJ,GAC7BM,EAAIV,GAAaQ,GAAO,EAAK,KAAUJ,GACvCO,EAAIX,GAAkB,IAANQ,GAAkBJ,UAC9BG,EAAS,IAAI,KAAOI,EAAKD,GAAK,EAAMT,GAAK,IAAKW,SAAS,IAGhE,QAAgBC,GAAarF,MAGxBsF,GAAS,mHADA,uCAECC,KAAKvF,IAAWsF,EAAOC,KAAKvF,GC7B3C,QAASwF,GAAEzJ,EAAMC,SACO,gBAATD,IAAoBC,GAAOC,UAAUC,cAAcH,GAAQA,GAAQ,KAGlF,QAAgB0J,GAAUC,EAAK3B,MAC1B3H,GAAUH,SAAS0J,gBAAgB,6BAA8BD,OAEhE,GAAIzC,KAAKc,GAAG,IACZ6B,GAAM7B,EAAEd,MAEF,WAANA,IACD2C,GAAKC,YAAYzJ,OAEf,IAAU,WAAN6G,EAAgB,IACpB6C,GAAMN,EAAEI,KACRG,WAAWC,aAAa5J,EAAS0J,KAC7BD,YAAYC,OAEJ,WAAN7C,EACQ,qBAAR2C,iBAAAA,YACFK,KAAKL,GAAKM,IAAI,cACZC,MAAMC,GAAQR,EAAIQ,MAInB,cAANnD,MAAyB,SACnB,cAANA,IACF,YAAyB2C,IAEjBS,aAAapD,EAAG2C,UAKpBxJ,GAGR,QAASkK,GAAuBC,EAAYC,SACpCf,GAAU,yBACRc,KACJC,KACA,KACA,KACA,KACA,IAIN,QAASC,GAAgBC,EAAUC,EAAQhC,EAAOiC,SAC1CnB,GAAU,eACNiB,uBACc/B,SACdgC,iBACMC,IAIlB,QAAgBC,GAAiBC,EAAQC,EAAWC,EAAOtF,SACnD+D,GAAU,iBACLsB,SACHD,QACDE,SACCtF,IAIV,QAAgBuF,GAAYC,SACpBzB,GAAU,eACRyB,IAIV,QAAgBC,GAAaJ,MAAWK,0DAAU,GAAIN,6DAAOjG,GACxDwG,aACQN,YACAK,SAETN,KAAQO,EAAKC,OAASR,GAClBrB,EAAU,IAAK4B,GAWvB,QAAgBE,GAASC,SACjB/B,GAAU,yEAD0B,KAGvC+B,wEAHkD,mEAAa,6EAAoB,KAYxF,QAAgBC,GAAeC,EAAeC,EAAaC,EAAQxH,MAAQyH,0DAAU,EAAGC,yDAAS,EAC3FC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAOjG,EAAI+F,EAAc/F,EAC9EuG,EAAqBN,EAAOI,EAAIL,EAAYK,EAAnCG,EAAsCP,EAAOjG,EAAIgG,EAAYhG,YAChEiG,EAAOI,MAAKJ,EAAOjG,YAC1BoG,MAAaE,aACZ7H,MAAUA,QAAY0H,OAAYD,EAAY,EAAI,YACpDK,MAAWC,OAGf,QAAgBC,GAAcV,EAAeC,EAAaC,EAAQxH,MAAQyH,0DAAU,EAAGC,yDAAS,EAC1FC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAOjG,EAAI+F,EAAc/F,EAC9EuG,EAA6BN,EAAOI,EAAIL,EAAYK,EAA3CK,EAAyD,EAAXT,EAAOjG,EAA7CwG,EAAoDP,EAAOjG,EAAIgG,EAAYhG,YACtFiG,EAAOI,MAAKJ,EAAOjG,YAC1BoG,MAAaE,aACZ7H,MAAUA,QAAY0H,OAAYD,EAAY,EAAI,YACpDK,MAAWG,cACVN,MAAaM,aACZjI,MAAUA,QAAY0H,OAAYD,EAAY,EAAI,YACpDK,MAAWC,OAGf,QAAgBG,GAAqBZ,EAAeC,EAAaC,EAAQxH,MAAQyH,0DAAU,EAAGC,yDAAS,EACjGC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAOjG,EAAI+F,EAAc/F,EAC9EuG,EAAqBN,EAAOI,EAAIL,EAAYK,EAAnCG,EAAsCP,EAAOjG,EAAIgG,EAAYhG,YAEhEoG,MAAaE,aACnB7H,MAAUA,QAAY0H,OAAYD,EAAY,EAAI,YACpDK,MAAWC,EAGf,QAAgBI,GAAoBb,EAAeC,EAAaC,EAAQxH,MAAQyH,0DAAU,EAAGC,yDAAS,EAChGC,EAAyBH,EAAOI,EAAIN,EAAcM,EAAvCC,EAA0CL,EAAOjG,EAAI+F,EAAc/F,EAC9EuG,EAA6BN,EAAOI,EAAIL,EAAYK,EAA3CK,EAAuD,EAATjI,EAAa6H,EAAnDE,EAA8DP,EAAOjG,EAAI+F,EAAc/F,YAElGoG,MAAaE,aACnB7H,MAAUA,QAAY0H,OAAYD,EAAY,EAAI,YACpDK,MAAWG,YACVN,MAAaM,aACZjI,MAAUA,QAAY0H,OAAYD,EAAY,EAAI,YACpDK,MAAWC,EAGf,QAAgBK,GAAajC,EAAY5B,MAAO8D,2DAC3CjC,EAAY,sBAA6B7B,EAAQ,KAAM8D,EAAU,UAAY,WAC7EC,EAAcpC,EAAuBC,EAAYC,GACjDmC,GAAa,EAAG,GAAK,UACtBF,QACW,GAAK,GAAK,MAGRC,EAAa,KAAM/D,EAAOgE,EAAU,MACpCD,EAAa,MAAO/D,EAAOgE,EAAU,MACrCD,EAAa,OAAQ/D,EAAOgE,EAAU,IAE/CnC,EAGR,QAAgBoC,GAAcZ,EAAGrG,EAAGqF,EAAOtF,MAC1CmH,0DAAMC,GAA8BjJ,yDAAK,aAkBlC4F,GAAU,kBAfL,mBACRuC,IACArG,QACIqF,SACCtF,OACF7B,iBAEK6E,EAAmB7E,GAAO,8BAGV6B,EAASsF,QAAUA,OAAUtF,iBACvCmH,KAOnB,QAAgBE,GAAWhC,EAAWiB,EAAGrG,EAAGqH,EAAM5I,MAAQP,0DAAK,OAAQoJ,4DAClE5B,aACQN,IACRiB,IACArG,QACIqH,SACCA,KACJ5I,OACEP,iBAGAoG,KAAKgD,GAAM/C,IAAI,cAChB/E,GAAO8H,EAAK9H,KAGXsE,EAAU,OAAQ4B,GAG1B,QAAgB6B,GAAUlB,EAAGrG,EAAGqH,MAAMnJ,0DAAK,OAAQwC,yEAC/BL,EAAeK,EAAO8G,IAAmB9G,KAExDgF,cACQ,eACR,IACA,QACI2B,SACC,WACFnJ,GAEHuJ,EAAO3D,EAAU,kBACT,wBACR,IACA,KACc,EAAZ4D,GAAiB,iBACI,IAAZA,GAAmB,mBAClB,aACTC,aACKjH,IAGRkH,EAAQ9D,EAAU,4BACGuC,OAAMrG,iBAEzBkE,YAAYJ,EAAU,OAAQ4B,MAC9BxB,YAAYuD,GAEXG,EAGR,QAAgBC,GAAUxB,EAAGrG,EAAGqH,MAAMnJ,0DAAK,OAAQwC,yEAC/BL,EAAeK,EAAO8G,IAAmB9G,KAExDgF,cACQ,gBACP,KACA,IACD2B,OACGnJ,GAEHuJ,EAAO3D,EAAU,kBACT,wBACR,IACA,KACE4D,GAAa,QACbA,GAAU,EAAK,iBACM,IAAZA,GAAmB,mBAClB,aACTC,aACKjH,IAGRkH,EAAQ9D,EAAU,4BACGuC,OAAMrG,iBAEzBkE,YAAYJ,EAAU,SAAU4B,MAChCxB,YAAYuD,GAEXG,EAGR,QAAgBE,GAAS1C,EAAWiB,EAAGrG,EAAG+H,MAASC,6DAC9CC,EAAWD,EAAQC,UAAYP,SAI5B5D,GAAU,kBACLsB,IACRiB,IACArG,UANoBd,KAAf8I,EAAQE,GAAmBF,EAAQE,GAAMD,EAAW,GAOnD,iBACIA,EAAW,UAPdD,EAAQ9J,MAAQyJ,iBACVK,EAAQG,YAAc,kBAS3BJ,IAIb,QAASK,GAAa/B,EAAG3F,EAAO2H,EAAIC,MAAIN,4DACnCA,GAAQO,SAAQP,EAAQO,OAASC,OACjCzH,GAAI+C,EAAU,kBACN,iBAAmBkE,EAAQ5C,aAClC,KACA,KACAiD,KACAC,iBAEKN,EAAQO,UAIdd,EAAO3D,EAAU,UACjB,IACAuE,EAAKC,EAAKD,EAAKI,GAAeJ,EAAKI,GAAef,MACjDA,GAAY,iBACHA,GAAY,mBACV,mBACJhH,EAAQ,KAGhBc,EAAOsC,EAAU,4BACKuC,oBAGrBnC,YAAYnD,KACZmD,YAAYuD,GAEVjG,EAGR,QAASkH,GAAa1I,EAAGU,EAAOiI,EAAIC,MAAIZ,4DACnCA,GAAQO,SAAQP,EAAQO,OAASC,IACjCR,EAAQa,WAAUb,EAAQa,SAAW,IACrCb,EAAQc,iBAAgBpI,EAAQD,EAAmBC,OAKnDK,GAAI+C,EAAU,kBAHF,mBAAqBkE,EAAQ5C,WACtB,WAArB4C,EAAQa,SAAwB,SAAU,OAIvCF,KACAC,KACA,KACA,iBAEKZ,EAAQO,UAIdd,EAAO3D,EAAU,UACjB6E,EAAKC,EAAKD,EAAKF,GAAeE,EAAKF,KACnC,KACEf,GAAY,EAAI,EAAK,iBACbA,GAAY,mBACViB,EAAKC,EAAK,MAAQ,kBACtBlI,EAAM,KAGdc,EAAOsC,EAAU,+BACO9D,uBACT,UAGP,KAATyH,GAAuB,MAATA,MACXjD,MAAM+D,OAAS,2BAGhBrE,YAAYnD,KACZmD,YAAYuD,GAEVjG,EAGR,QAAgBuH,GAAM/I,EAAGU,EAAO2E,MAAO2C,4DACjCnJ,GAAcmB,KAAIA,EAAI,GAEvBgI,EAAQgB,MAAKhB,EAAQgB,IAAM,QAC3BhB,EAAQhD,SAAQgD,EAAQhD,OAAS,GACjCgD,EAAQiB,OAAMjB,EAAQiB,KAAO,QAC7BjB,EAAQO,SAAQP,EAAQO,OAASC,IACjCR,EAAQ5C,YAAW4C,EAAQ5C,UAAY,OAEvCuD,IAAM,EAAIO,GACVN,EAAsB,SAAjBZ,EAAQiB,KAAkB5D,EAAQ6D,GAAmB,QAE1C,SAAjBlB,EAAQiB,MAAmC,UAAhBjB,EAAQgB,QAChC3D,EAAQ6D,KACR7D,MAKA2C,EAAQhD,UACRgD,EAAQhD,OAEP0D,EAAa1I,EAAGU,EAAOiI,EAAIC,UACzBZ,EAAQO,iBACLP,EAAQ5C,mBACT4C,EAAQa,wBACFb,EAAQc,iBAI1B,QAAgBK,GAAM9C,EAAG3F,EAAOX,MAAQiI,4DAClCnJ,GAAcwH,KAAIA,EAAI,GAEvB2B,EAAQgB,MAAKhB,EAAQgB,IAAM,UAC3BhB,EAAQhD,SAAQgD,EAAQhD,OAAS,GACjCgD,EAAQiB,OAAMjB,EAAQiB,KAAO,QAC7BjB,EAAQO,SAAQP,EAAQO,OAASC,IACjCR,EAAQ5C,YAAW4C,EAAQ5C,UAAY,OAavCiD,GAAKtI,EAASmJ,GACdZ,EAAsB,SAAjBN,EAAQiB,MAAmB,EAAIC,GAAmBnJ,QAEvC,SAAjBiI,EAAQiB,MAAmC,QAAhBjB,EAAQgB,SAE/B,EAAIE,KACL,GAGCd,EAAa/B,EAAG3F,EAAO2H,EAAIC,UACzBN,EAAQO,iBACLP,EAAQ5C,mBACT4C,EAAQa,WAIpB,QAAgBO,GAAQpJ,EAAGU,EAAO2E,MAAO2C,4DACpCA,GAAQqB,WAAUrB,EAAQqB,SAAW,YAIrCC,GAAWxF,EAAU,kBACb,gBAJiB,SAArBkE,EAAQqB,SAAsBZ,GACnCpD,EAAQjH,EAAesC,EAAO,GAAK+H,KAKlC,KACEf,IAAa,EAAK,iBACVA,GAAY,mBACV,kBACJhH,EAAM,KAGdc,EAAOkH,EAAa1I,EAAG,GAAI,EAAGqF,UACzB2C,EAAQO,QAAUC,aACfR,EAAQ5C,WAAa,YACtB4C,EAAQa,oBAGd3E,YAAYoF,GAEV9H,EAGR,QAAgB+H,GAAQlB,EAAIC,EAAIjD,EAAO3E,MAAOsH,6DAEzCjI,EAASsI,EAAKC,EAEd5N,EAAOoJ,EAAU,6EAIX0E,sBACenD,OAAUtF,KAG/B,IACA,QACIsF,SACCtF,GAGLiI,GAAQqB,WAAUrB,EAAQqB,SAAW,YAIrCC,GAAWxF,EAAU,kBACb,gBAJiB,SAArBkE,EAAQqB,SAAsBZ,GACnCpD,EAAQjH,EAAesC,EAAM,GAAI,KAAO+H,KAKvC,KACEf,IAAa,EAAK,iBACVA,GAAY,mBACV,kBACJhH,EAAM,KAGd8I,EAAS1F,EAAU,+BACKwE,iBAGrBpE,YAAYxJ,KACZwJ,YAAYoF,GAEZE,EAGR,QAAgBC,GAAWpD,EAAGxG,EAAMwF,EAAOrC,MAAOtC,0DAAM,GAAIgJ,yDAAM,EAAG1E,yDAAO,EAAG2E,8DAC5D/J,EAAqBC,EAAM8J,EAAK7J,oBAA7CC,OAAQC,UACRgF,EAES,IAAXjF,MACO4J,EAAKC,aACTD,EAAKC,WAIN/K,EAAcwH,KAAIA,EAAI,GACtBxH,EAAcmB,KAAIA,EAAI,GACtBnB,EAAckB,GAAQ,KAAOA,EAAS,GACtClB,EAAcwG,GAAO,KAAOA,EAAQ,MAErC3K,GAAOoJ,EAAU,4CAEJd,qBACI0G,IACjBrD,IACArG,QACIqF,SACCtF,WAGA,KAEKW,EAAM7C,OAEb,GACD6G,aAAa,IAAK,KAClBA,aAAa,IAAK,MACnB+C,GAAO3D,EAAU,kBACT,qBACRuB,EAAM,IACN,KACEqC,GAAY,GAAK,EAAK,iBACdA,GAAY,mBACV,mBACJhH,IAGRkH,EAAQ9D,EAAU,wBACD4F,yBACIrD,OAAMrG,iBAEzBkE,YAAYxJ,KACZwJ,YAAYuD,GAEXG,QArBAlN,GAyBT,QAAgBmP,GAAWxD,EAAGrG,EAAGvB,EAAQuE,MAAOtC,0DAAM,GAAIgJ,yDAAM,EAC3DI,EAAMhG,EAAU,yBACHd,qBACI0G,KAChBrD,KACArG,IACDvB,WAGK,KAEKiC,EAAM7C,OAEb,GACF6G,aAAa,KAAM,KACnBA,aAAa,KAAM,MAEnB+C,GAAO3D,EAAU,kBACT,qBACR,IACA,KACE4D,GAAY,GAAK,EAAIjJ,EAAU,iBACvBiJ,GAAY,mBACV,mBACJhH,IAGRkH,EAAQ9D,EAAU,wBACD4F,yBACIrD,OAAMrG,iBAEzBkE,YAAY4F,KACZ5F,YAAYuD,GAEXG,QAtBAkC,GA0BT,QAAgBC,GAAS5I,EAAOC,EAAO4B,MAAOgF,6DAAY2B,4DAErDK,EADa5I,EAAMmD,IAAI,SAACvE,EAAGsB,SAAOH,GAAMG,GAAK,IAAMtB,IAC5BiK,KAAK,IAG5BjC,GAAQkC,SACXF,EAAY9I,EAAwBC,EAAOC,OAExC+I,GAAOvE,EAAS,IAAIoE,EAAW,kBAAmBhH,MAGnDgF,EAAQoC,SAAU,IAChBC,GAAcxD,EAAa8C,EAAKW,QAAStH,KACxCwB,MAAM+D,eAAiB8B,SAGzBE,SACGJ,MAIJnC,EAAQwC,WAAY,IAClBC,GAAqB5D,EAAa8C,EAAKW,QAAStH,GAAO,GAEvD6C,EAAU,IAAS1E,EAAM,OAAMwI,EAAK7J,aAAckK,MAAgB7I,EAAMX,OAAO,GAAG,OAAMmJ,EAAK7J,WAC3F0J,OAAS5D,EAASC,gBAAwB,eAAgB4E,aAG1DF,GChmBR,QAAgBG,GAAUC,EAAMC,EAAUC,EAAUC,MAC/CC,GAA0B,gBAAbH,GAAwBA,EAAWA,EAASX,KAAK,aAEjEU,GACClF,UAAWoF,EAASZ,KAAK,OAC1Ba,EACAE,GACA,aACCvF,UAAWsF,IAId,QAAgBE,GAAkB9B,EAAO+B,EAAMC,SACvCT,GAAUvB,GAAQgC,EAAM,IAAKD,EAAM,GAAIE,IAG/C,QAAgBC,IAAkBtC,EAAOuC,EAAMC,SACvCb,GAAU3B,GAAQ,EAAGwC,IAAQ,EAAGD,GAAOF,IAG/C,QAAgBI,IAAcC,EAAWC,EAAOC,EAAOC,MAClDC,GAAYH,EAAQC,EACpBjR,EAAO+Q,EAAUK,WAAW,WAG/BpR,GACEqF,OAAQ8L,EAAWE,mBAHVrR,EAAKsR,aAAa,cAGyBH,GACtDT,GACAJ,IAGeN,EAAUe,GAAY,EAAGG,IAAS,EAAGD,GAAQP,KAI9D,QAAgBa,IAAWC,EAAK7F,EAAGxG,EAAMwF,MAAOL,0DAAO,IACpCpF,EAAqBC,8DAAWC,oBAA7CC,OAAQC,iBACRgF,EACe,SAAjBkH,EAAIC,WACKD,EAAIJ,WAAW,IAGxBzG,MAAOA,EAAOtF,OAAQA,GACvBqM,GACApB,IAIeN,EAAUwB,EADRA,EAAIF,aAAa,aAAaK,MAAM,KAAK,GAAG7L,MAAM,GAAI,IAC3B6F,EAAGrG,GAAIoL,OAG3Cc,GAAM7G,MAAOA,EAAOtF,OAAQA,EAAQsG,EAAGA,EAAGrG,EAAGA,GAAIoM,GAAepB,KAK3E,QAAgBsB,IAAWxC,EAAKzD,EAAGrG,SACd,WAAjB8J,EAAIqC,UAEUzB,EAAUZ,EADRA,EAAIkC,aAAa,aAAaK,MAAM,KAAK,GAAG7L,MAAM,GAAI,IAC3B6F,EAAGrG,GAAIoL,OAG3CtB,GAAMyC,GAAIlG,EAAGmG,GAAIxM,GAAIoM,GAAepB,KAK/C,QAAgByB,IAAYlC,EAAOmC,EAAUC,EAAU7M,EAAUoK,MAC5D0C,MACA5C,EAAY2C,EAASpI,IAAI,SAACvE,EAAGsB,SAAOoL,GAASpL,GAAK,IAAMtB,IAAIiK,KAAK,IAEjEC,KACHF,EAAY9I,EAAwBwL,EAAUC,OAEzCE,IAAYtC,EAAMJ,MAAO5M,EAAE,IAAMyM,GAAY8C,GAAe9B,SACnDzJ,KAAKsL,GAEjBtC,EAAMf,OAAQ,IACZuD,GAAgBL,EAAS,OAAM5M,MAC/BkN,MAAeN,EAASlM,OAAO,GAAG,QAAOV,EAEvCmN,GACL1C,EAAMf,QACLjM,EAAE,IAAMwP,EAAa/C,EAAYgD,GAClCF,GACA9B,MAEczJ,KAAK0L,SAGdL,GAGR,QAAgBM,IAAeC,EAAStH,UAC/BsH,GAAU5P,EAAGsI,GAAUuG,GAAepB,IC1F/C,QAASoC,IAAkB3S,EAAS4S,EAAOC,MAAKC,0DAAW,SAAUjR,6DAAK4C,GAAWsO,4DAEhFC,EAAchT,EAAQiT,WAAU,GAChCC,EAAalT,EAAQiT,WAAU,OAE/B,GAAIE,KAAiBP,GAAO,IAC3BQ,YACiB,cAAlBD,EACetT,SAAS0J,gBAAgB,6BAA8B,oBAEvD1J,SAAS0J,gBAAgB,6BAA8B,cAErE8J,GAAeN,EAAUI,IAAkBnT,EAAQuR,aAAa4B,GAChErO,EAAQ8N,EAAMO,GAEdG,iBACYH,OACTE,KACFvO,QACG,SACF+N,EAAI,IAAO,WACRQ,EAAe,IAAMvO,aACjByO,GAAOT,YACT,eACA,cACJ,SAGJjR,OACF,KAAmBA,OAGf,GAAIgF,KAAKyM,KACErJ,aAAapD,EAAGyM,EAASzM,MAG7B4C,YAAY2J,GAErBvR,IACSoI,aAAakJ,eAA4BrO,SAEzCmF,aAAakJ,EAAerO,UAIjCkO,EAAaE,GAGtB,QAAgBlI,IAAUhL,EAAS+J,KAC1BA,MAAMiB,UAAYjB,IAClBA,MAAMyJ,gBAAkBzJ,IACxBA,MAAM0J,YAAc1J,IACpBA,MAAM2J,aAAe3J,IACrBA,MAAM4J,WAAa5J,EAG5B,QAAS6J,IAAW9I,EAAc+I,MAC7BC,MACAC,OAEKjK,IAAI,eACRoG,GAAOlQ,EAAQ,GACf0K,EAASwF,EAAKvG,WAEdqJ,SAAaE,WAET,GAAKhD,QACeyC,mBAAqB3S,8BAErC8G,KAAKoM,KACJpM,MAAMkM,EAAatI,IAE5BA,KACIsJ,aAAahB,EAAa9C,QAI/B+D,GAAUnJ,EAAamI,WAAU,YAExBnJ,IAAI,SAACkJ,EAAanM,GAC1BmM,EAAY,OACH,GAAGgB,aAAaF,EAAYjN,GAAImM,EAAY,MAC/CnM,GAAG,GAAKiN,EAAYjN,MAIxBoN,EAGR,QAAgBC,IAAiBxJ,EAAQyJ,EAAYC,MACpB,IAA7BA,EAAkBhR,WAEjBiR,GAAiBT,GAAWO,EAAYC,EACzCD,GAAWxK,YAAce,MACpB4J,YAAYH,KACZ1K,YAAY4K,eAKT,WACPA,EAAe1K,YAAce,MACxB4J,YAAYD,KACZ5K,YAAY0K,KAElBI,KCnHG,QAASC,IAAaC,EAAU5H,MAClC5E,GAAIpI,SAAS6U,cAAc,OAC7B3K,MAAQ,mBACN4K,GAAO,GAAIC,MAAK/H,GAAOhL,KAAM,iCAC7BgT,EAAM/T,OAAOgU,IAAIC,gBAAgBJ,KACnCK,KAAOH,IACPI,SAAWR,WACJnU,KAAKmJ,YAAYxB,KACxBiN,mBACS,oBACD5U,KAAKgU,YAAYrM,UACnB6M,IAAIK,gBAAgBN,IACzB,KAGJ,QAAgBO,IAAiBC,MAC5BC,GAAQD,EAAIpC,WAAU,KACpBsC,UAAUC,IAAI,qBACdvL,aAAa,QAAS,gCACtBA,aAAa,cAAe,mCAC9BwL,GAAUrM,EAAEsM,OAAO,mBACTC,OAER/L,aAAa6L,EAASH,EAAMM,eAE9BC,GAAYzM,EAAEsM,OAAO,gBACfjM,YAAY6L,GAEfO,EAAUC,UCblB,QAASC,IAAWC,MACfC,GAAS,GAAIjR,MAAKgR,YACfE,WAAWD,EAAOE,aAAeF,EAAOG,qBACxCH,EAGR,QAAgBI,IAAYL,MACvBM,GAAKN,EAAKO,UACVC,EAAKR,EAAKS,WAAa,SAE1BT,EAAKU,eACJF,EAAG,EAAI,GAAK,KAAOA,GACnBF,EAAG,EAAI,GAAK,KAAOA,GACnB9G,KAAK,KAGR,QAAgB8F,IAAMU,SACd,IAAIhR,MAAKgR,EAAK/Q,WAiBtB,QAAgB0R,IAAgBC,EAAWC,MACtCC,GAAgBC,GAAeH,SAC5BrT,MAAKyT,KAAKC,GAAeH,EAAeD,GAAWK,IAG3D,QAAgBD,IAAeL,EAAWC,MACrCM,GAAqBC,GAAaC,UAC9BtB,GAAWc,GAAWd,GAAWa,IAAcO,EAGxD,QAAgBG,IAAeV,EAAWC,SAClCD,GAAUH,aAAeI,EAAQJ,YACpCG,EAAUF,gBAAkBG,EAAQH,cAGzC,QAAgBa,IAAa1Q,MAAG2Q,2DAC3BC,EAAYC,GAAY7Q,SACrB2Q,GAAQC,EAAU1R,MAAM,EAAG,GAAK0R,EAGxC,QAAgBE,IAAoBC,EAAOC,SACnC,IAAI7S,MAAK6S,EAAMD,EAAQ,EAAG,GAIlC,QAAgBb,IAAef,MAC1B8B,GAAUxC,GAAMU,GACd+B,EAAMD,EAAQE,eACT,KAARD,MACMD,GAAW,EAAKC,GAElBD,EAIR,QAAgBG,IAAQjC,EAAMkC,KACxBC,QAAQnC,EAAKO,UAAY2B,GC6V/B,QAAgBE,IAAaC,EAAMC,EAAWC,MACzC1O,GAAO2O,OAAO3O,KAAK4O,IAAkBC,OAAO,kBAAKL,GAAKM,SAASC,KAC/DC,EAASJ,GAAiB5O,EAAK,kBAC5BiP,OAAOD,aACFP,UACFC,IAEH,GAAIQ,IAAeF,GC1b3B,QAASG,IAAUpN,MAKX,IAAJA,SACM,EAAG,MAETpH,MAAMoH,UACAqN,UAAW,iBAAkBC,SAAU,QAE5CC,GAAMvN,EAAI,EAAI,GAAK,MACnBlH,SAASkH,UACJqN,SAAgB,iBAANE,EAAwBD,SAAU,OAGjD3V,KAAKC,IAAIoI,MACTwN,GAAM7V,KAAK6C,MAAM7C,KAAK8C,MAAMuF,WAGxBuN,GAFEvN,EAAErI,KAAKiD,IAAI,GAAI4S,IAENA,GAGpB,QAASC,IAAuBC,MAAKC,0DAAI,EACpCC,EAAajW,KAAKyT,KAAKsC,GACvBG,EAAalW,KAAK6C,MAAMmT,GACxBG,EAAQF,EAAaC,EAErBE,EAAYD,EACZE,EAAW,CAGZF,GAAQ,IACPA,EAAQ,GAAM,UAGKD,KAEVC,EAAM,IACP,GAITA,GAAS,MAEAA,KADC,IAKA,IAAVA,MACU,IACD,OAIR,GADAG,MACIhT,EAAI,EAAGA,GAAK8S,EAAW9S,MACpBC,KAAK2S,EAAaG,EAAW/S,SAEjCgT,GAGR,QAASC,IAAkBC,MAAUC,0DAAS,IACZhB,GAAUe,aAAtCE,OAAgBf,OACjBgB,EAAiBF,EAAWA,EAASzW,KAAKiD,IAAI,GAAI0S,GAAW,EAK7DW,EAAYR,KAFCY,EAAelX,QAAQ,GAEemX,YAC3CL,EAAU/P,IAAI,kBAAShF,GAAQvB,KAAKiD,IAAI,GAAI0S,KAIzD,QAAgBiB,IAAmBC,WAYzBC,GAA0BN,EAAUO,OAOxC,GANAT,GAAYC,GAAkBC,GAE9BQ,EAAeV,EAAU,GAAKA,EAAU,GAGxC/U,EAAQ,EACJ+B,EAAI,EAAG/B,EAAQwV,EAAazT,OAC1B0T,IACCC,SAAU,EAAK1V,SAEnB+U,MAvBkCY,2DAMtCV,EAAWxW,KAAK+V,kBAAOc,IACvBJ,EAAWzW,KAAKgW,kBAAOa,IAGTP,QAkBfE,GAAY,GAAKC,GAAY,EACpBhB,GAAUe,GAAU,KAC3BU,EAGSX,GAAkBC,EAAUC,GAF5BF,GAAkBC,OAQ3B,IAAGA,EAAW,GAAKC,EAAW,EAAG,IAOjCM,GAAc/W,KAAKC,IAAIwW,EAExBD,IAAYO,GACHtB,GAAUe,GAAU,KACnBM,EAA0BN,EAAUO,KAGrCtB,GAAUsB,GAAa,KACfD,EAA0BC,EAAaP,GACjCrS,UAAUoC,IAAI,mBAAW,EAANhH,SAOzC,IAAGiX,GAAY,GAAKC,GAAY,EAAG,IAInCU,GAAiBnX,KAAKC,IAAIwW,GAC1BW,EAAiBpX,KAAKC,IAAIuW,EAEnBf,IAAU0B,GAAgB,QACjCD,EAGSX,GAAkBY,EAAgBC,GAFlCb,GAAkBY,IAKThT,UAAUoC,IAAI,mBAAW,EAANhH,UAGnC+W,GAGR,QAAgBe,IAAaC,MAExBC,GAAWC,GAAgBF,SAC5BA,GAAKG,QAAQ,IAAM,EAGTH,EAAKG,QAAQ,GAChBH,EAAK,GAAK,GAIL,EADJA,EAAK,GACUC,GAKX,EADJD,EAAKA,EAAKzX,OAAS,GACJ0X,GAAYD,EAAKzX,OAAS,GAiBrD,QAAgB2X,IAAgBE,SACxBA,GAAa,GAAKA,EAAa,GAGvC,QAAgBC,IAAcD,SACtBA,GAAaA,EAAa7X,OAAO,GAAK6X,EAAa,GAG3D,QAAgBE,IAAM3R,EAAK4R,SACnBvY,GAASuY,EAAM/V,SAAWmE,EAAM4R,EAAMC,iBAY9C,QAAgBC,IAAkBC,EAAMC,MAAKvM,2DACxCwM,EAAUD,EAAI1T,OAAO,SAAS4T,EAAMC,SAC/BpY,MAAKC,IAAImY,EAAOJ,GAAQhY,KAAKC,IAAIkY,EAAOH,GAAQI,EAAOD,aAGzDzM,GAAQuM,EAAIR,QAAQS,GAAWA,EAGvC,QAAgBG,IAAiBxB,EAAQyB,OASpC,GALAC,GAAevY,KAAK+V,kBAAOc,IAE3B2B,EAAmB,GAAKF,EAAmB,GAC3CG,KAEInV,EAAI,EAAGA,EAAIgV,EAAkBhV,IAAK,IACrCoV,GAAaH,GAAgBC,EAAmBlV,KACvCC,KAAKmV,SAGZD,GAGR,QAAgBE,IAAiBpX,EAAOkX,SAChCA,GAAatD,OAAO,kBAAK5V,GAAIgC,IAAO1B,OC1OrC,QAAS+Y,IAAStP,EAAMhL,KACzBua,OAASvP,EAAKuP,cAEfC,GAAgBxP,EAAKuP,OAAOhZ,OAG5BkZ,EAAWzP,EAAKyP,SAChBC,EAAY,GAAIjZ,OAAM+Y,GAAe5Y,KAAK,SAC1C6Y,gBAGMC,OAIDzS,IAAI,eAERhH,EAAEsX,OAEC,IAEFoC,GAAO1Z,EAAEsX,YACNoC,EAAK1S,IAAI,kBAAStF,OAAMgF,GAAa,EAANA,KAG9BpG,OAASiZ,EACTG,EAAKzW,MAAM,EAAGsW,GAEdrZ,EAAUwZ,EAAMH,EAAgBG,EAAKpZ,OAAQ,KAEnDgX,OAASoC,SAZTpC,OAASmC,CAgBRzZ,GAAE2Z,YACDC,GAAyB/D,SAAS9W,KACpC4a,UAAY5a,KASbgL,EAAK8P,YACFA,SAAS7S,IAAI,eACdhH,EAAE8Z,IAAM9Z,EAAEK,MAAO,QACCL,EAAE8Z,IAAK9Z,EAAEK,SAA1BA,aAASyZ,YAKR/P,EAGR,QAAgBgQ,IAAaC,MACxBT,GAAgBS,EAASV,OAAOhZ,OAChCmZ,EAAY,GAAIjZ,OAAM+Y,GAAe5Y,KAAK,GAE1CsZ,UACKD,EAASV,OAAOrW,MAAM,GAAI,YACxB+W,EAASR,SAASxS,IAAI,wBAExB,UACEyS,EAAUxW,MAAM,GAAI,aACjBjD,EAAE2Z,oBAKbK,GAASE,aACFA,iBAEA,QACA,MAKPF,EAASH,aACFA,iBAEA,MACF,QACE,MAKHI,EAGR,QAAgBE,IAAmBC,MAAYd,6DAAWe,6DACrDC,EAAeF,EAAad,EAAOhZ,MACpCga,IAAgB,IAAGA,EAAe,MACjCC,GAAiBD,EAAeE,GAEhCC,YACDJ,EAAU,IAERK,GAAiBja,KAAK+V,kBAAO8C,EAAOtS,IAAI,kBAAS7D,GAAM7C,aAC1CG,KAAKyT,KAAKwG,EAAeH,SAG1BjB,GAAOtS,IAAI,SAAC7D,EAAOY,aAC1B,IACAzD,OAASia,IAEbF,EAOAtW,EAAI0W,GAAmB,MACjB,MAPNF,EAAe,EAAI,EACbpX,EAAMF,MAAM,EAAGsX,EAAe,GAAK,OAEnCpX,EAAMF,MAAM,EAAGsX,GAAkB,MAQrCpX,ICzGT,QAASwX,SAAehB,0DAAY,OAAQ/R,eAAQ6C,qBACjC,eAAdkP,KACK5a,KAAO,OACR,GAAI6b,IAAUhT,EAAQ6C,IAGzBoQ,GAAWlB,GAKT,GAAIkB,IAAWlB,GAAW/R,EAAQ6C,gBAJhCqQ,MAAM,yBAA2BnB,IC1B3C,SAAqBoB,EAAKnU,OACX,KAARA,IAAiBA,KACtB,IAAIoU,GAAWpU,EAAIoU,QAEnB,IAAKD,GAA2B,mBAAbhe,UAAnB,CAEA,GAAIke,GAAOle,SAASke,MAAQle,SAASme,qBAAqB,QAAQ,GAC9DjU,EAAQlK,SAAS6U,cAAc,QACnC3K,GAAMlI,KAAO,WAEI,QAAbic,GACEC,EAAKnI,WACPmI,EAAKnU,aAAaG,EAAOgU,EAAKnI,YAKhCmI,EAAKtU,YAAYM,GAGfA,EAAMkU,WACRlU,EAAMkU,WAAWC,QAAUL,EAE3B9T,EAAMN,YAAY5J,SAASse,eAAeN,46IdT9CzU,GAAEsM,OAAS,SAACpM,EAAK3B,MACZ3H,GAAUH,SAAS6U,cAAcpL,OAEhC,GAAIzC,KAAKc,GAAG,IACZ6B,GAAM7B,EAAEd,MAEF,WAANA,IACD2C,GAAKC,YAAYzJ,OAEf,IAAU,WAAN6G,EAAgB,IACpB6C,GAAMN,EAAEI,KACRG,WAAWC,aAAa5J,EAAS0J,KAC7BD,YAAYC,OAEJ,WAAN7C,EACQ,qBAAR2C,iBAAAA,YACFK,KAAKL,GAAKM,IAAI,cACZC,MAAMC,GAAQR,EAAIQ,KAGlBnD,IAAK7G,KACP6G,GAAK2C,IAGLS,aAAapD,EAAG2C,SAInBxJ,GCxBD,IAAMoe,kBAEN,UACG,QACF,SACC,kBAGF,UACG,QACF,SACC,eAGI,gBACC,gBACC,iBAEC,IAyBHC,GAA4B,IAI5B3B,IAA4B,OAAQ,OAWpChQ,GAA+B,EAS/B4Q,GAAqB,EAI5BgB,IAAwB,aAAc,OAAQ,SAAU,MAAO,SACpE,SAAU,QAAS,cAAe,SAAU,UAAW,aAAc,aAKzDC,QACPD,QACCA,OACDA,cACOA,YARiB,UAAW,UAAW,UAAW,UAAW,iBAUlEA,IAIKpa,GAAcX,KAAKqE,GAAK,IctGhB4W,oCAEnB9T,OAAAA,aAAS,WACT+T,OAAAA,kCAEK/T,OAASA,OACT+T,OAASA,OACTC,UAAY,QACZC,WAAa,QACbC,mBACAC,gBAAkB,OAElBjT,EAAI,OACJrG,EAAI,OAEJpF,IAAM,OACNI,KAAO,OAEPue,wDAIAC,qDAIAtb,YACAub,qEAIAnJ,UAAYzM,EAAEsM,OAAO,cACjBuJ,KAAKvU,iBACF,8JAKPwU,eAEAC,MAAQF,KAAKpJ,UAAU/V,cAAc,eACrCsf,cAAgBH,KAAKpJ,UAAU/V,cAAc,yBAE7C4K,OAAO2U,iBAAiB,aAAc,aACrCH,sDAKFC,QACDF,MAAKhQ,YACF4G,UAAU5L,aAAa,mBAAoBgV,KAAKhQ,SAEnDgQ,KAAKJ,2BACYI,KAAKN,uBAAsBM,KAAKP,UAExCO,KAAKP,qBAAoBO,KAAKN,4BAErCQ,MAAMrJ,UAAYqJ,OAClBC,cAActJ,UAAY,QAE1B8I,WAAW9U,IAAI,SAACwV,EAAKzY,MACnB0B,GAAQgX,EAAKd,OAAO5X,IAAM,QAC5B/B,EAA0B,IAAlBwa,EAAIE,WAAmBF,EAAIE,UAAYF,EAAIE,UAAYF,EAAIxa,MAEnE2a,EAAKrW,EAAEsM,OAAO,wCAEWnN,iDAE6B,IAAVzD,GAAeA,EAAQA,EAAQ,6BAC3Ewa,EAAIH,MAAQG,EAAIH,MAAQ,QAGvBC,cAAc3V,YAAYgW,+CAK5B7U,GAAQqU,KAAKpJ,UAAU6J,iBAEtBvf,IAAM8e,KAAK1Z,EAAI0Z,KAAKpJ,UAAU8J,adIU,OcFxCpf,KAAO0e,KAAKrT,EAAIhB,EAAM,KACvBgV,GAAUX,KAAKvU,OAAOgV,YAAc9U,EAEpCiV,EAAUZ,KAAKpJ,UAAU/V,cAAc,mBAExCmf,KAAK1e,KAAO,IACNwJ,MAAMxJ,oBAAsB,EAAI0e,KAAK1e,gBACxCA,KAAO,MACN,IAAG0e,KAAK1e,KAAOqf,EAAS,IAE1BE,kBADQb,KAAK1e,KAAOqf,WAEhB7V,MAAMxJ,KAAOuf,OAEhBvf,KAAOqf,SAEJ7V,MAAMxJ,6CAINqL,EAAGrG,MAAG4Z,6DAAYP,4DAAiB3P,0DAAS,OAChDyP,UAAYS,EAAM9G,UAClBsG,WAAaQ,EAAMra,WACnB8Z,WAAaA,OACbhT,EAAIA,OACJrG,EAAIA,OACJsZ,gBAAkBM,EAAMY,YAAc,OACtC9Q,MAAQA,OACR+Q,iDAIAnK,UAAU9L,MAAM5J,IAAM,WACtB0V,UAAU9L,MAAMxJ,KAAO,WACvBsV,UAAU9L,MAAMS,QAAU,2CAI1BqL,UAAU9L,MAAM5J,IAAM8e,KAAK9e,IAAM,UACjC0V,UAAU9L,MAAMxJ,KAAO0e,KAAK1e,KAAO,UACnCsV,UAAU9L,MAAMS,QAAU,aX5H3ByV,iBACS,eACN,iBACE,cACH,iBACG,iBACA,gBACD,wBACM,iBACL,kBACC,gBACF,eACD,uBACM,sBACD,WA8BDvX,GAAW,SAACH,SAEpB,4BAA6BY,KAAKZ,iCACE2X,KAAK3X,GAC1CuB,IAAI,SAAC8B,EAAG/E,SAAa,KAANA,EAAUtC,OAAOqH,GAAG5C,SAAS,IAAM,MAClDlB,OAAO,SAACqY,EAAGC,YAAUD,EAAIC,IAErBH,GAAiB1X,IAAUA,GC9CtBkG,GAAmB,EAC1BT,GAAe,EACfjB,GAAkB,GACXE,GAAY,GACnBc,GAAkB,UAClBb,GAAY,UAkmBPmT,QACH,SAACnQ,MACHoQ,SACiB,UAAlBpQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBkP,GAAUrQ,EAAK+C,qBACXlJ,MAAMtG,KAAO,YACbsG,MAAMS,QAAU,MAErB8V,KACMrW,aAAa,YAAaqW,GAE5BC,OAGD,SAACrQ,MACHoQ,SACiB,YAAlBpQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBkP,GAAUrQ,EAAK+C,YACfjP,EAASkM,EAAKqB,aAAa,KAC3B9N,EAAOyM,EAAKqB,aAAa,iBACrBtH,aAAa,IAAKpB,SAAS7E,GJ7jBA,KI8jB3BiG,aAAa,OAAQxG,KACrBsG,MAAMS,QAAU,MAErB8V,KACMrW,aAAa,YAAaqW,GAE5BC,eAGO,SAACrQ,MACXoQ,SACiB,YAAlBpQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBkP,GAAUrQ,EAAK+C,YACfjP,EAASkM,EAAKqB,aAAa,KAC3B9N,EAAOyM,EAAKqB,aAAa,iBACrBtH,aAAa,IAAKpB,SAAS7E,GJhlBA,KIilB3BiG,aAAa,OAAQxG,KACrBsG,MAAMS,QAAU,MAErB8V,KACMrW,aAAa,YAAaqW,GAE5BC,IAIEC,QACH,SAACtQ,EAAMqQ,MACTD,SACiB,UAAlBpQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBoP,IAAc,IAAK,IAAK,QAAS,iBAC9BrG,OAAOlK,EAAKuQ,YACjB/H,OAAO,kBAAQ+H,GAAW9H,SAAS+H,EAAKrI,OAASqI,EAAKC,YACtD7W,IAAI,cACIG,aAAayW,EAAKrI,KAAMqI,EAAKE,aAGpCN,KACMrW,aAAa,YAAaqW,QAI7B,SAACpQ,EAAMqQ,MACTD,SACiB,YAAlBpQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBoP,IAAc,KAAM,aACjBrG,OAAOlK,EAAKuQ,YACjB/H,OAAO,kBAAQ+H,GAAW9H,SAAS+H,EAAKrI,OAASqI,EAAKC,YACtD7W,IAAI,cACIG,aAAayW,EAAKrI,KAAMqI,EAAKE,aAGpCN,KACMrW,aAAa,YAAaqW,gBAIrB,SAACpQ,EAAMqQ,MACjBD,SACiB,YAAlBpQ,EAAKwB,aACUxB,EAAKqB,aAAa,eAC5BrB,EAAKmB,WAAW,OAEpBoP,IAAc,KAAM,aACjBrG,OAAOlK,EAAKuQ,YACjB/H,OAAO,kBAAQ+H,GAAW9H,SAAS+H,EAAKrI,OAASqI,EAAKC,YACtD7W,IAAI,cACIG,aAAayW,EAAKrI,KAAMqI,EAAKE,aAGpCN,KACMrW,aAAa,YAAaqW,KCrtBxB3O,GAAgB,IAChBU,GAAgB,IAChB1B,GAAuBgB,GACvB4C,GAAsB,IAEtBhE,GAAa,SCHpBgD,SACC,yBACE,iBAEA,wBACC,uBACE,iBSVCoC,GAAU,0sDCUFkL,yBACRnW,EAAQ6C,mBAET3I,EAAU2I,QAEf7C,OAA2B,gBAAXA,GAClB7K,SAASC,cAAc4K,GACvBA,IAEGuU,KAAKvU,iBAAkBoW,mBACtB,IAAIC,OAAM,uDAGZC,aAAezT,OAEf4R,MAAQ5R,EAAQ4R,OAAS,QACzBtd,KAAO0L,EAAQ1L,MAAQ,QAEvBib,SAAWmC,KAAKgC,YAAY1T,EAAQV,WACpCA,KAAOoS,KAAKiC,iBAAiBjC,KAAKnC,eAElC2B,OAASQ,KAAKkC,eAAe5T,EAAQkR,OAAQQ,KAAKpd,WAElDgX,oBACS,aACD,cACCtL,EAAQ6T,aAAe,cACC,KAApB7T,EAAQ8T,QAA2B9T,EAAQ8T,QAAU,kBACrD9T,EAAQ+T,iBAAmB,QAGxCC,SAAWC,KAAKC,MAAMD,KAAKE,UAAUtD,QACtC/b,GAAI4c,KAAKsC,cACRI,YAAYpU,GACb0R,KAAKE,MAAM/b,WAAYd,YAAc,GACrC2c,KAAKpG,OAAO+I,aAAYvf,EAAEM,aAAe,QACxCkf,UAAYtU,EAAQjI,QAAUjD,EAAEyf,gBAEhCC,cACAxU,gBAEAyU,YAAc3D,GAEhBY,KAAKpG,OAAOuI,mBACTa,kBAGDC,UAAU3U,kDAGJV,SACJA,4CAGSA,SACTA,0CAGO4R,EAAQ5c,MAChBsgB,gBACI1D,OAAc/a,OAAO6a,GAAe1c,KACvCugB,QAAQ,SAACxe,MACT2E,GAAQG,GAAS9E,EACnBqF,GAAaV,KAGJzB,KAAKyB,WAFT8Z,KAAK,IAAMze,EAAS,6BAKvBue,wFASH7c,EAAS2Z,KAAK4C,eACbC,WAAaxc,OACbA,OAASA,EAAS5C,EAAeuc,KAAKsC,eAGtCe,YAAc,iBAAMC,GAAKC,MAAK,IAC/BC,sBACEC,eAAiB,GAAID,gBAAexD,KAAKqD,kBACzCI,eAAeC,QAAQ1D,KAAKvU,gBAE3B2U,iBAAiB,SAAUJ,KAAKqD,oBAChCjD,iBAAiB,oBAAqBJ,KAAKqD,+CAI9CrD,KAAKyD,gBAAgBzD,KAAKyD,eAAeE,oBACtCC,oBAAoB,SAAU5D,KAAKqD,oBACnCO,oBAAoB,oBAAqB5D,KAAKqD,kDAKhDQ,qBACAC,mBACAhE,mBAEAyD,MAAK,GAAO,gDAKZ9X,OAAOoL,UAAY,MAEpB7K,WACKgU,KAAKvU,iBACF,kBAGTuU,MAAK+D,qBACF3hB,QAAWuJ,MAAOqU,KAAK+D,iBAAmB,YAG3CnN,UAAYzM,EAAEsM,OAAO,MAAOzK,8CAI5BgY,IAAM,GAAIzE,YACNS,KAAKpJ,iBACLoJ,KAAKR,cAETyE,+FAKDC,0DAAuBC,yDACvBD,IAAmB1iB,EAASwe,KAAKvU,eAIhCqY,mBAEAM,KAAKF,QACLG,qBACAC,uBAEAC,WAAWpB,QAAQ,kBAAKjC,GAAErB,MAAMS,EAAKkE,iBAErCC,OAAOzE,KAAKuE,YAAY,GAE1BJ,SACGvW,KAAOoS,KAAKnC,oBACN,aAAY6G,OAAOpE,EAAK1S,OAASoS,KAAK+C,mBAG7C4B,oBAEAC,gBAAgBT,+EAMhBU,UAAY1iB,EAAuB6d,KAAKvU,aACxCE,MAAQqU,KAAK6E,UAAYlhB,EAAcqc,KAAKsC,kDAI9CtC,KAAK5J,UACFQ,UAAUvB,YAAY2K,KAAK5J,QAE7BhT,GAAI4c,KAAKsC,cAERlM,IAAM5K,EACVwU,KAAKpJ,UACL,qBACAoJ,KAAK6E,UACL7E,KAAK6C,iBAEDjS,QAAUhF,EAAYoU,KAAK5J,KAE7B4J,KAAKE,MAAM/b,cACR2gB,QAAU1W,EACd,QACAhL,EAAEE,QAAQhC,KACV8B,EAAEE,QAAQpC,IACV8e,KAAKE,gBAEM9c,EAAE2hB,mBACN,aACF3hB,EAAE2hB,oBAKL7jB,GAAMiC,EAAaC,QAClBohB,SAAW1Y,EACfkU,KAAKpd,KAAO,sCACCY,EAAcJ,QAAOlC,OAGhC8e,KAAKpG,OAAO+I,gBACP3C,KAAK3Z,OAASjD,EAAEG,SAAS3B,YAC3BojB,WAAalZ,EACjB,4BACatI,EAAcJ,QAAOlC,QAIjC8e,KAAKE,MAAM/b,aAAeiS,IAAI5L,YAAYwV,KAAK8E,cAC7C1O,IAAI5L,YAAYwV,KAAKwE,UACvBxE,KAAKpG,OAAO+I,iBAAmBvM,IAAI5L,YAAYwV,KAAKgF,iBAElDC,gBAAgBzhB,EAAcJ,GAAID,EAAaC,4CAGrCuJ,EAAGrG,QACb0d,IAAI1Y,UACLqB,IACArG,kDAIoBie,WAAa,GAAIW,oCAEnCtX,GACFA,WACK+Q,MAAM,2BAEV/Q,KAAOoS,KAAKgC,YAAYpU,QACxBwW,YACAK,OAAOzE,KAAKuE,WAAYvE,KAAKpG,OAAOwI,cACpCuC,2DAGCJ,yDAAWvE,KAAKuE,WAAYnC,4DAC/BpC,MAAKpG,OAAOuI,kBAETa,SAASnY,IAAI,kBAAKnC,GAAEgC,WAAW2K,YAAY3M,QAG7CyM,QAEOgO,QAAQ,cACEhO,EAAkB1Q,OAAOyc,EAAEwD,OAAOtC,MAEpDjN,EAAkBhR,OAAS,MACZ6b,KAAKpJ,UAAWoJ,KAAK5J,IAAKjB,cAChC,aACCgO,QAAQ,kBAAKjC,GAAEiE,WACrBC,ahBpMiC,SgBuM5BjC,QAAQ,kBAAKjC,GAAEiE,cACrBC,iDAKHpF,KAAKpG,OAAOuI,mBACTf,mBACAiE,0GAMSlB,yDACXnE,MAAKpG,OAAOuI,aAEbgC,SACGmB,mBAEAC,eACEvF,KAAKwF,WAAWC,KAAKzF,SACrBA,KAAK0F,YAAYD,KAAKzF,SACtBA,KAAK2F,UAAUF,KAAKzF,SACpBA,KAAK4F,aAAaH,KAAKzF,SACvBA,KAAK6F,YAAYJ,KAAKzF,gBAGpBI,iBAAiB,UAAW,SAAC0F,GAClCnkB,EAAoBokB,EAAKnP,eACvBkP,GAAKjkB,OAAOmkB,MACbD,EAAKR,WAAWO,EAAEG,YACfV,WAAWO,EAAEG,mmBA2BlBC,GAAW/P,GAAiB6J,KAAK5J,QACxB4J,KAAKE,OAAS,SAAUgG,aC3TlBC,0BACR1a,EAAQO,+EACbP,EAAQO,yDAGLA,4FACOA,QAEX4N,OAAOwM,gBAAkBpa,EAAKqa,oBAAsBD,oBACpDxM,OAAO0M,UAAYta,EAAKsa,WAAa,QACrC1M,OAAO2M,gBAAkBva,EAAKua,iBAAmB,6CAIlDC,EAAIxG,KAAK8C,MACTwD,EAAYtG,KAAKpG,OAAO0M,YAC1BG,kBAEEC,GAAY1G,KAAKpS,KAAKuP,OAAOtS,IAAI,SAAC7D,EAAOY,MACxC+e,GAAQ,WACP/Y,KAAKyP,SAASxS,IAAI,eACbib,EAAE3K,OAAOvT,MAEX+e,EAAO3f,KACbyS,OAAO,kBAAc5V,GAAE,IAAM,IAE5B+iB,EAASF,KACVA,EAAUviB,OAASmiB,EAAW,GAEtBO,KAAK,SAAC7d,EAAGa,SAAeA,GAAE,GAAKb,EAAE,OAElC0d,EAAU5f,MAAM,EAAGwf,EAAU,MAGlCQ,GAAiB,CAFLJ,GAAU5f,MAAMwf,EAAU,GAGhCzb,IAAI,eAAwBhH,EAAE,OACjCgE,MAAMif,EAAgB,cACxBtH,OAAO8G,EAAU,GAAK,SAG1BnJ,YACKtS,IAAI,cACR4b,YAAY5e,KAAKnC,EAAM7B,EAAE,OACzBsZ,OAAOtV,KAAKhE,EAAE,QAGfkjB,WAAaP,EAAEC,YAAY5d,OAAO,SAACG,EAAGa,SAAMb,GAAIa,GAAG,QAEhD0C,UACDyT,KAAKrU,MAAQ,IACbqU,KAAK3Z,OAAS,qDAKdmgB,EAAIxG,KAAK8C,WACRkC,WAAWgC,YAAc,QACzBC,aAAeT,EAAEC,YAAY3f,MAAM,EAAGkZ,KAAKpG,OAAO2M,oBAEnDtiB,GAAQ,EACRqC,EAAI,OACH2gB,aAAapc,IAAI,SAAChH,EAAG+D,MACrBsf,GAAW,IACXC,EAAU7iB,KAAK6C,OACjBigB,EAAKzb,MAAQhI,EAAcyjB,EAAK9E,WAAW4E,EAEzCE,GAAKH,aAAa9iB,OAASgjB,MACnBC,EAAKzb,MAAMyb,EAAKH,aAAa9iB,QAEtCF,EAAQkjB,MACF,KACH,OAEFxa,GAAIua,EAAWjjB,EAAQ,EACvB+C,EAAQogB,EAAKxN,OAAOyI,gBAAkB1b,EAAe6f,EAAErJ,OAAOvV,GAAIsf,EAAS,IAAMV,EAAErJ,OAAOvV,GAC1F2Y,EAAY6G,EAAKxN,OAAOwM,eAAiBgB,EAAKxN,OAAOwM,eAAeviB,GAAKA,EACzEuM,EAAMjC,EACTxB,EACArG,EACA,EACA8gB,EAAK5H,OAAO5X,GACTZ,OAAUuZ,GACb,KAEIyE,WAAWxa,YAAY4F,gBApFewR,ITHjC3J,GAAqB,EAErBG,GAAe,IACfD,GAAa,MAEbM,IAAe,UAAW,WAAY,QAAS,QAAS,MACpE,OAAQ,OAAQ,SAAU,YAAa,UAAW,WAAY,YAIlD4O,IAAmB,MAAO,MAAO,MAAO,MAAO,MAAO,MAAO,OCNpEvN,oCAEJwN,WAAAA,aAAa,SACbC,eAAAA,aAAiB,KACjBlO,IAAAA,UAEAC,IAAAA,QACAkO,IAAAA,aACAC,IAAAA,gCAEKF,eAAiBA,OACjBlO,UAAYA,OAEZmO,aAAeA,OACflO,QAAUA,OAEVmO,gBAAkBA,OAElBC,cACAvK,eAEAmK,WAAaA,OACbA,WAAyC,kBAArBtH,MAAKsH,WAC3BtH,KAAKsH,aAAetH,KAAKsH,gBAEvBvG,qDAGEnT,QACFA,KAAOA,GAAQoS,KAAK1G,wCAGpB7N,QACAkc,MAAQ7b,EAAakU,KAAKsH,WAAYtH,KAAKuH,eAAgB9b,uCAI3DgZ,OAAOzE,KAAKpS,WACZga,QAAU5H,KAAKpS,oCAGdA,mBACD8Z,MAAQ1H,KAAKwH,aAAa5Z,QAE1B+Z,MAAMX,YAAc,QACpBU,MAAMvE,QAAQ,cACbwE,MAAMnd,YAAYzJ,UAEnBoc,OAAOgG,QAAQ,cACdwE,MAAMnd,YAAYzJ,yCAIlBqhB,mEACDrB,aACD0G,YACDrF,OACgBpC,KAAKyH,gBAAgBzH,KAAKpS,WAEtC6Z,WAILjO,4BAEU,qCACC5L,SACLA,GAAKia,aAAahd,IAAI,SAAC2b,EAAG5e,MAC5Bd,GAAQoF,EAASsa,EAAG,aAAc5Y,EAAK4R,OAAO5X,GAAI,OAAQgG,EAAKka,sBAC7Dhd,MAAMid,WAAa,iBAClBjhB,8BAIOkhB,SACRhI,MAAK0H,MAAM7c,IAAI,SAAC/D,EAAOc,SAAM4L,IAAe1M,EAAOkhB,EAAQH,aAAajgB,8BAIpE,mCACCgG,SACLA,GAAKia,aAAahd,IAAI,SAAC2b,EAAG5e,MAC5Bd,GAAQoF,EAASsa,EAAG,WAAY,OAAQ5Y,EAAK4R,OAAO5X,aAClDkD,MAAMid,WAAa,iBAClBjhB,8BAIOkhB,SACRhI,MAAK0H,MAAM7c,IAAI,SAAC/D,EAAOc,SAC7B4L,IAAe1M,EAAOkhB,EAAQH,aAAajgB,mCAKjC,wCACCgG,oBACLA,GAAKqa,WAAWpd,IAAI,SAAC8B,EAAG/E,SAEpB2F,GAAcZ,EADhB,EACsBiB,EAAKsa,OAAOtgB,GACzC0Y,EAAKjH,UAAU8O,UAAW7H,EAAKjH,UAAU+O,SAAUxa,EAAK4R,OAAO5X,gCAKlDogB,MACZA,EAAS,6BAID,+BACCpa,oBACLA,GAAKya,UAAUxd,IAAI,SAACyd,EAAU1gB,SACpCyH,GAAMiZ,EAAU1a,EAAKuP,OAAOvV,GAAIwf,EAAK/N,UAAU1N,OAC7C4D,KAAM6X,EAAK/N,UAAU9J,KAAMD,IAAK8X,EAAK/N,UAAU/J,IAAKF,eAAgBgY,EAAK/N,UAAUjK,6CAIvE4Y,MACXO,GAASP,EAAQK,UACjBG,EAAYR,EAAQ7K,OACpBsL,EAASzI,KAAK4H,QAAQS,UACtBK,EAAY1I,KAAK4H,QAAQzK,SAEV5W,EAAqBkiB,EAAQF,iCACvBhiB,EAAqBmiB,EAAWF,uCAEpD/D,kBACOgE,SACHD,IAGFxI,KAAK0H,MAAM7c,IAAI,SAAC/C,EAAMF,SACrB+J,IACN7J,EAAMygB,EAAO3gB,GAAI6gB,EAAO7gB,0BAOf,+BACCgG,oBACLA,GAAKya,UAAUxd,IAAI,SAACyd,EAAU1gB,SACpC6H,GAAM6Y,EAAU1a,EAAK+a,WAAW/gB,GAAIme,EAAK1M,UAAUhT,QACjDkJ,KAAMwW,EAAK1M,UAAU9J,KAAMD,IAAKyW,EAAK1M,UAAU/J,kCAInC0Y,MACXO,GAASP,EAAQK,UACjBG,EAAYR,EAAQW,WACpBF,EAASzI,KAAK4H,QAAQS,UACtBK,EAAY1I,KAAK4H,QAAQe,aAEVpiB,EAAqBkiB,EAAQF,iCACvBhiB,EAAqBmiB,EAAWF,uCAEpD/D,kBACOgE,aACCD,IAGNxI,KAAK0H,MAAM7c,IAAI,SAAC/C,EAAMF,SACrB2J,GACNzJ,EAAMygB,EAAO3gB,GAAI6gB,EAAO7gB,6BAOf,kCACCgG,oBACLA,GAAK/C,IAAI,kBACf6E,GAAQtM,EAAEklB,SAAUllB,EAAE4D,MAAO4hB,EAAKvP,UAAU1N,OAC1CgE,SAAUvM,EAAEkL,QAAQqB,SAAUJ,KAAM,OAAQJ,SAAU,uCAG1C6Y,SACWzhB,EAAqByZ,KAAK4H,QAASI,kBAAvDJ,gBAEFW,YAAiB1d,IAAI,kBAAKhH,GAAEykB,WAC5BE,EAAYR,EAAQnd,IAAI,kBAAKhH,GAAEmD,QAC/B6hB,EAAab,EAAQnd,IAAI,kBAAKhH,GAAEyK,UAEhCma,EAASzI,KAAK4H,QAAQ/c,IAAI,kBAAKhH,GAAEykB,uBAEhC7D,OAAOgE,EAAO5d,IAAI,SAACyE,EAAK1H,mBAEjB6gB,EAAO7gB,SACV4gB,EAAU5gB,WACRihB,EAAWjhB,OAIfoY,KAAK0H,MAAM7c,IAAI,SAAC/C,EAAMF,SACrB+J,IACN7J,EAAMygB,EAAO3gB,GAAI6gB,EAAO7gB,6BAOf,kCACCgG,oBACLA,GAAK/C,IAAI,kBACfgF,GAAQzG,EAAE0f,SAAU1f,EAAE2f,OAAQC,EAAK3P,UAAU1N,MAC5CvC,EAAEpC,OAAQ2I,SAAUvG,EAAEkF,QAAQqB,uCAGjBqY,SACWzhB,EAAqByZ,KAAK4H,QAASI,kBAAvDJ,gBAEFW,YAAiB1d,IAAI,kBAAKhH,GAAEklB,SAC5BP,EAAYR,EAAQnd,IAAI,kBAAKhH,GAAEmD,QAC/BiiB,EAAYjB,EAAQnd,IAAI,kBAAKhH,GAAEilB,WAC/BD,EAAab,EAAQnd,IAAI,kBAAKhH,GAAEyK,UAEhCma,EAASzI,KAAK4H,QAAQ/c,IAAI,kBAAKhH,GAAEklB,SACjCG,EAAYlJ,KAAK4H,QAAQ/c,IAAI,kBAAKhH,GAAEilB,gBAEnCrE,OAAOgE,EAAO5d,IAAI,SAACyE,EAAK1H,mBAEjBshB,EAAUthB,UACZ6gB,EAAO7gB,SACR4gB,EAAU5gB,WACRihB,EAAWjhB,UAIlB6f,kBAECC,MAAM7c,IAAI,SAACkH,EAAWnK,KACR6f,EAAgBhjB,OAAOqN,GACxCC,EAAWkX,EAAUrhB,GAAI2gB,EAAO3gB,GAAI6gB,EAAO7gB,OAItC6f,2BAKI,iBAAoB,sBAAwBzH,KAAK3G,UAAUrJ,6BAC1DpC,gBACuDoS,KAAK3G,UAAnErJ,IAAAA,MAAOmZ,IAAAA,SAAUC,IAAAA,UAAWC,IAAAA,WAAYtkB,IAAAA,OAEzC4H,IAFiD2c,WAEjChjB,EAAI,cAEnBijB,0BAEAC,KAAK3e,IAAI,SAAC4e,EAAMC,GACN,IAAXA,KACGvM,OAAOtV,KACXuG,EAAS,cAAezB,GARL,GAQyB2L,GAAatI,GAAO,GAAM2Z,wBAE1D,OAKT9e,IAAI,SAACiO,EAAKlR,MACXkR,EAAItU,KAAM,IACRoJ,gBACUkL,EAAI8Q,sBACH9Q,EAAI+Q,qBACNjiB,GAETkiB,EAASpc,EAAW,MAAOf,EAAGrG,EAAG+iB,EAAYtkB,EAAQ+T,EAAItU,KAAMoJ,KAC9D2b,qBAAqB1hB,KAAKiiB,MAE3BV,MAEF,KACCD,IAGCnJ,KAAKuJ,+CAGGvB,MACZA,EAAS,gCAKD,iBAAoB,sCAAwChI,KAAK3G,UAAUrJ,6BAC1EpC,MACRsT,GAAIlB,KAAK3G,sBACR0Q,SAAW,WACXC,MAAQpc,EAAKqc,WAAWpf,IAAI,SAACvE,EAAGrD,SAC7B8M,GACNnC,EAAKqa,WAAWhlB,GAChBqD,EACAsH,EAAKsZ,SACLhG,EAAE5X,MACFsE,EAAKuP,OAAOla,GACZA,EACA2K,EAAKsc,QAAQjnB,aAEF2K,EAAKxH,mBACJwH,EAAKuc,oBACLjJ,EAAEhR,cAIT8P,KAAKgK,gCAEGhC,MACXoC,GAAUpC,EAAQC,WAClBoC,EAAUrC,EAAQiC,WAClBK,EAAatC,EAAQkC,QACrB1B,EAAYR,EAAQ7K,OAEpBoN,EAAUvK,KAAK4H,QAAQK,WACvBuC,EAAUxK,KAAK4H,QAAQqC,WACvBQ,EAAazK,KAAK4H,QAAQsC,QAC1BxB,EAAY1I,KAAK4H,QAAQzK,SAER5W,EAAqBgkB,EAASH,iCAC9B7jB,EAAqBikB,EAASH,iCACxB9jB,EAAqBkkB,EAAYH,iCACnC/jB,EAAqBmiB,EAAWF,gCAEpD/D,mBACQ8F,aACAC,UACHC,SACDjC,WAEExI,KAAK4H,QAAQxhB,mBACZ4Z,KAAK4H,QAAQuC,mBACdnK,KAAK4H,QAAQV,cAGpBO,kBAECC,MAAM7c,IAAI,SAAC2H,EAAK5K,KACF6f,EAAgBhjB,OAAO8N,GACxCC,EAAK4X,EAAQxiB,GAAIyiB,EAAQziB,GAAIogB,EAAQd,SAAUoD,EAAW1iB,IACzDxB,SAAU4hB,EAAQ5hB,cAIdqhB,0BAKI,iBAAoB,sCAAwCzH,KAAK3G,UAAUrJ,6BAC1EpC,MACRsT,GAAIlB,KAAK3G,sBACR0Q,SAAW,WACXlZ,SACDqQ,EAAEwJ,gBACA7Z,MAAQR,EACZzC,EAAKqa,WACLra,EAAKqc,WACL/I,EAAE5X,gBAES4X,EAAExQ,oBACAwQ,EAAEpQ,kBACNoQ,EAAE1Q,iBAGD0Q,EAAEtQ,iBACDhD,EAAKxH,iBAKb4jB,SACD9I,EAAEyJ,gBACAX,MAAQpc,EAAKqc,WAAWpf,IAAI,SAACvE,EAAGrD,SAC7BkN,GACNvC,EAAKqa,WAAWhlB,GAChBqD,EACAsH,EAAK7I,OACLmc,EAAE5X,MACD4X,EAAE0J,iBAAmBhd,EAAKuN,OAAOlY,GAAK,GACvCA,MAKIsW,OAAO4B,OAAO6E,KAAKnP,OAAOpM,OAAOub,KAAKgK,iCAE9BhC,MACXoC,GAAUpC,EAAQC,WAClBoC,EAAUrC,EAAQiC,WAClBY,EAAY7C,EAAQ7M,OAEpBoP,EAAUvK,KAAK4H,QAAQK,WACvBuC,EAAUxK,KAAK4H,QAAQqC,WACvBnW,EAAYkM,KAAK4H,QAAQzM,SAER5U,EAAqBgkB,EAASH,iCAC9B7jB,EAAqBikB,EAASH,iCAC1B9jB,EAAqBuN,EAAW+W,gCAEpDpG,mBACQ8F,aACAC,SACJK,WAEE7K,KAAK4H,QAAQxhB,gBACf4Z,KAAK4H,QAAQ7iB,YAGlB0iB,YAEDlO,QAAO3O,KAAKoV,KAAKnP,OAAO1M,WACRsjB,EAAgBhjB,OAAOsO,GACxCiN,KAAKnP,MAAOuZ,EAASC,EAASrC,EAAQ5hB,SAAU4Z,KAAK3G,UAAU7I,UAG9DwP,KAAKgK,MAAM7lB,aACR6lB,MAAMnf,IAAI,SAACuF,EAAKxI,KACF6f,EAAgBhjB,OAAOmO,GACxCxC,EAAKga,EAAQxiB,GAAIyiB,EAAQziB,OAIrB6f,KS3aWqD,0BACRrf,EAAQO,8EACbP,EAAQO,aACTpJ,KAAO,eACPid,iEAGMvR,MACPlL,GAAI4c,KAAKsC,cACRyI,WAAazc,EAAQyc,kBAEtBlhB,GAAImW,KAAK+K,aACX1kB,OAASwD,EAAExD,QlB0D8B,KkBzDzCmH,MAAQ3D,EAAE2D,OAASC,KAEnBlK,SAASvB,MAAQ,KACjB0B,aAAe,KACfmf,WAA0C,GAA5BhZ,EAAExD,OAAmB,GAAVwD,EAAE2D,oDAIzBgZ,GAAIxG,KAAK8C,MAETtJ,IAEF,4BAEYwG,KAAK+K,WAAW1kB,gBACjB2Z,KAAK+K,WAAWvd,OAE3B,6BAEcgZ,EAAEyB,kBACNzB,EAAE0B,cACFlI,KAAKR,SAEbiG,KAAKzF,aAIJuE,WAAa,GAAIW,KAAI1L,EACxB3O,IAAI,eACAmgB,GAAY7R,mBAAgBnN,WACxBA,EAAK,GAAIgf,wIAMfxE,GAAIxG,KAAK8C,QAEXmF,gBACAC,aAEE+C,GAAO,IACTxE,YAAY5b,IAAI,SAAChF,MACd8F,GAAQ2U,EAAK3U,MAAQ9F,EAAQ2gB,EAAEO,aACjCmB,OAAOrgB,KAAK8D,KACZsc,WAAWpgB,KAAKojB,MACVtf,gGAOL6a,EAAIxG,KAAK8C,WACRlM,UAAUwJ,iBAAiB,YAAa,SAAC0F,MACzCoF,GAAO9D,EAAK7C,WAAW4G,IAAI,kBAAkBzD,MAC7ClV,EAAMsT,EAAEnjB,UACTuoB,EAAKxR,SAASlH,GAAM,IAElB5K,GAAIsjB,EAAKnP,QAAQvJ,GACjB4Y,EAAOtqB,EAAUsmB,EAAKxQ,WAAYyU,EAAOvqB,EAAU0R,GAEnD7F,EAAI0e,EAAK/pB,KAAO8pB,EAAK9pB,KAAOsI,SAAS4I,EAAIF,aAAa,UAAU,EAChEhM,EAAI+kB,EAAKnqB,IAAMkqB,EAAKlqB,IACpBgf,GAASkH,EAAKkE,iBAAmBlE,EAAKkE,gBAAgBnnB,OAAO,EAC9DijB,EAAKkE,gBAAgB1jB,GAAKwf,EAAKtE,MAAM3F,OAAOvV,IAAM,KACjD2jB,EAAW/E,EAAEC,YAAY7e,GAAG4e,EAAEO,aAE7B/C,IAAIwH,UAAU7e,EAAGrG,GAAI8S,KAAM8G,EAAOra,OAAiB,IAAT0lB,GAAcznB,QAAQ,GAAK,QACrEkgB,IAAIyH,oBAlFgCtF,ICIxBuF,0BACRjgB,EAAQO,8EACbP,EAAQO,aACTpJ,KAAO,QACPmgB,YAAc,IACdoB,KAAO,IAEPtE,+DAGI7T,4FACOA,QACX2f,UAAY3L,KAAK2L,UAAUlG,KAAKzF,WAChC4L,WAAa5L,KAAK4L,WAAWnG,KAAKzF,WAElC6L,WAAa7f,EAAK6f,YAAc,QAChCjS,OAAOkS,WAAa9f,EAAK8f,YAAc,OAEvCtf,UAAYR,EAAKQ,YAAa,oIAK/Bga,GAAIxG,KAAK8C,WACR/d,OAAUib,KAAK3Z,OAAS2Z,KAAKrU,MAAQqU,KAAKzT,OAAOI,EAAIqT,KAAKzT,OAAOjG,KAE9DvB,GAAsBib,KAAtBjb,OAAQyH,EAAcwT,KAAdxT,UAEVuf,EAAuBvF,EAAEwF,uBAC7BnE,kBACAmE,uBACEC,GAAW,IAAMjM,KAAKpG,OAAOkS,aAC/BrF,YAAY5b,IAAI,SAAC8b,EAAO/e,MACnBkkB,GAAaG,EACbC,EAAmBvF,EAAQH,EAAEO,WnB+DZ,ImB9DjBta,EAAWyf,EAAkB,IAAM,EAAG,EACtCC,EAAY3f,GAAa0f,EAAkBA,EAC3CE,EAAWH,GAAsBE,EACjC9f,EAAgBxH,EAAmBinB,EAAY/mB,GAC/CuH,EAAczH,EAAmBunB,EAAUrnB,GAE3CsnB,EAAe/L,EAAK6D,MAAQ4H,EAAqBnkB,GAEnD0kB,SAASC,QACVjM,GAAK6D,QACIkI,EAAeA,EAAahgB,cAAgBA,IAC9CggB,EAAeA,EAAa/f,YAAcD,MAExCA,IACFC,MAEJkgB,GACe,MAApBN,EACGnf,EAAcuf,EAAUC,EAAQjM,EAAK/T,OAAQ+T,EAAKvb,OAAQyH,EAAWC,GACrEL,EAAekgB,EAAUC,EAAQjM,EAAK/T,OAAQ+T,EAAKvb,OAAQyH,EAAWC,KAExEob,aAAahgB,KAAK2kB,KAClBR,iBAAiBnkB,0CAGX8e,QACAH,EAAEO,yCAGFoF,WAIJhI,KAAO,+CAIRqC,GAAIxG,KAAK8C,MAETtJ,IAEF,eAEA,+BAEgBgN,EAAEqB,oBACR7H,KAAKR,SAEbiG,KAAKzF,aAIJuE,WAAa,GAAIW,KAAI1L,EACxB3O,IAAI,eACAmgB,GAAY7R,mBAAgBnN,WACxBA,EAAK,GAAIgf,kDAIAyB,MACb1nB,GAAqBib,KAArBjb,OAAO8mB,EAAc7L,KAAd6L,WACPvD,EAAWzjB,EAAmB4nB,EAASX,WAAYW,EAAS3nB,MAAQ,EAAGC,wBACtDujB,EAAS3b,EAAKkf,QAAiBvD,EAAShiB,EAAKulB,6CAG1Dpb,EAAK7I,EAAE8kB,EAAK5G,MAClBrV,MACEnH,GAAQ0W,KAAKR,OAAO5X,MACvB8kB,EAAM,IACEjc,EAAMuP,KAAK2M,oBAAoB3M,KAAK8C,MAAMkJ,iBAAiBpkB,OAChEkD,MAAMtG,KAAO6E,EAAmBC,EAAO,OACxCsjB,GAAQ9rB,EAAUkf,KAAK5J,KACvBzJ,EAAImZ,EAAE+G,MAAQD,EAAMtrB,KAAO,GAC3BgF,EAAIwf,EAAEgH,MAAQF,EAAM1rB,IAAM,GAC1Bgf,GAASF,KAAK+M,kBAAoB/M,KAAK+M,iBAAiB5oB,OAAS,EAClE6b,KAAK+M,iBAAiBnlB,GAAKoY,KAAK8C,MAAM3F,OAAOvV,IAAM,KAClDolB,GAAuC,IAA5BhN,KAAK8C,MAAM2D,YAAY7e,GAAWoY,KAAK8C,MAAMiE,YAAYjjB,QAAQ,QAC3EkgB,IAAIwH,UAAU7e,EAAGrG,GAAI8S,KAAM8G,EAAOra,MAAOmnB,EAAU,WACnDhJ,IAAIyH,kBAEChb,EAAK,2BACVuT,IAAI/D,YACJnV,MAAMtG,KAAO8E,8CAKdsN,UAAUwJ,iBAAiB,YAAaJ,KAAK2L,gBAC7C/U,UAAUwJ,iBAAiB,aAAcJ,KAAK4L,8CAG1C9F,MACHnjB,GAASmjB,EAAEnjB,OACbsqB,EAASjN,KAAKuE,WAAW4G,IAAI,aAAazD,MAC1CwF,EAAYlN,KAAKmN,oBACjBC,EAAapN,KAAKqN,kBACnBJ,EAAOvT,SAAS/W,GAAS,IACvBiF,GAAIqlB,EAAOlR,QAAQpZ,QAClB2qB,WAAWF,EAAYF,GAAU,QACjCG,eAAiB1qB,OACjBwqB,oBAAsBvlB,OACtB0lB,WAAW3qB,EAAQiF,GAAG,EAAMke,aAE5B8F,uDAKD0B,WAAWtN,KAAKqN,eAAerN,KAAKmN,qBAAoB,UA/IzBhH,ICIjBoH,0BACR9hB,EAAQ6C,8EACb7C,EAAQ6C,MACT1L,KAAO,YAEP4qB,WAAalf,EAAQkf,YAAc,MAEpCC,IAAe,SAAU,UACzBC,EAAiBD,EAAY/T,SAASpL,EAAQof,gBAC/Cpf,EAAQof,eAAiB,kBACvBC,oBAAsBF,EAAY1R,QAAQ2R,KAE1C7N,iEAGMvR,MACPlL,GAAI4c,KAAKsC,cACRsL,gBAA8C,IAA5Btf,EAAQsf,gBAAwB,EAAI,IAEzDrqB,SAASrC,IAAM2sB,KACftqB,SAAS3B,OAAS,IAClB8B,aAAemqB,KACfhL,WA1BciL,GA0BY7V,GACzBxU,EAAeL,MAEdS,GAAImc,KAAKpS,KACTmgB,EAAU/N,KAAK4N,gBZrCY,GYqC0B,OACpD7J,iBA/BW+J,IA+BSpW,GAAgB7T,EAAEK,MAAOL,EAAE8Z,KACjDoQ,GAAuBpqB,EAAcP,4CAIpC2qB,GAAU/N,KAAK4N,gBZ3CY,GY2C0B,EACrDI,EAAYhO,KAAK8C,MAAMkL,UAAYhO,KAAK8C,MAAMkL,UAAY,QACzDnJ,UAtCWiJ,IAsCEE,EAAYD,GAC3BpqB,EAAcqc,KAAKsC,mDAGX1U,0DAAKoS,KAAKpS,QAClBA,EAAK1J,OAAS0J,EAAK+P,KAAO/P,EAAK1J,MAAQ0J,EAAK+P,SACxC,IAAImE,OAAM,kDAGblU,EAAK1J,UACHA,MAAQ,GAAI6B,QACZ7B,MAAM+pB,YAAargB,EAAK1J,MAAMuT,cAAgB,IAEhD7J,EAAK+P,QAAYA,IAAM,GAAI5X,SAC1BmoB,WAAatgB,EAAKsgB,eAEpBtkB,SAAS2P,OAAO3O,KAAKgD,EAAKsgB,YAAY,IAAM,IAAQ,IAClDvmB,aACGiD,KAAKgD,EAAKsgB,YAAY/K,QAAQ,eAChCpM,GAAO,GAAIhR,MAAKooB,EAAe/V,MAC5BhB,GAAYL,IAASnJ,EAAKsgB,WAAWC,OAExCD,WAAavmB,QAGZiG,qCAIH4Y,GAAIxG,KAAK8C,QAEX5e,MAAQmS,GAAM2J,KAAKpS,KAAK1J,SACxByZ,IAAMtH,GAAM2J,KAAKpS,KAAK+P,OAEtByQ,eAAiB/X,GAAMmQ,EAAEtiB,SACzB8pB,UAAYtW,GAAgB8O,EAAEtiB,MAAOsiB,EAAE7I,OACvCZ,aAAeJ,GAChBpD,OAAO4B,OAAO6E,KAAKpS,KAAKsgB,YpBJc,KoBMrCG,cAAgBrO,KAAKsO,kEAInB9H,EAAIxG,KAAK8C,MACTyL,EAAUvO,KAAK4N,gBAAkB,EAAI,EAErCpU,EAAmBgN,EAAE6H,cAAcxjB,IAAI,SAAC+O,EAAQhS,UACnD,oBAEQgS,EAAO5J,eAvFA8d,aAAAA,cpByEiB,UoBkBvBxN,EAAKyB,aAAahd,QAAU,aA3FtB+oB,GA4FFtH,EAAE6H,cACZ5U,OAAO,SAACG,EAAQ3W,SAAMA,GAAI2E,IAC1BiD,IAAI,kBAAU+O,GAAO4P,KAAKrlB,OAASoqB,IACnC1lB,OAAO,SAACG,EAAGa,SAAMb,GAAIa,GAAG,IAG3B,iBACQ2c,GAAE6H,cAAczmB,IACtB6d,KAAKnF,WAIHiE,WAAa,GAAIW,KAAI1L,EACxB3O,IAAI,SAACmB,EAAMpE,MACPojB,GAAY7R,mBAAgBnN,WACxBA,EAAK,GAAK,IAAMpE,EAAGojB,SAIzB1kB,GAAI,KACQ6c,QAAQ,SAACqL,EAAS5mB,OAC7B,EAAG,EAAG,GAAG8R,SAAS9R,GAAI,IACrB6mB,GAAUrgB,EAAS,kBAAkB,EAAc9H,EAAGkoB,YpBzC3B,MoB4CzB,aACQ,UAGThK,SAASha,YAAYikB,MAzHZX,oCA+HVlgB,GACFA,WACK+Q,MAAM,2BAGV/Q,KAAOoS,KAAKgC,YAAYpU,QACxB2V,YACAU,oEAIArN,UAAUwJ,iBAAiB,YAAa,SAAC0F,KACxCvB,WAAWpB,QAAQ,eACnBuL,GAAaC,EAAKjH,MAClBkH,EAAY9I,EAAEnjB,UACf+rB,EAAWhV,SAASkV,GAAY,IAE9B3qB,GAAQ2qB,EAAUtc,aAAa,cAC/Buc,EAAYD,EAAUtc,aAAa,aAAaK,MAAM,KAEtDgG,EAAQL,GAAa1O,SAASilB,EAAU,IAAI,GAAG,GAE/CzD,EAAOhE,EAAKxQ,UAAU3V,wBAAyBoqB,EAAOuD,EAAU3tB,wBAEhE0K,EAAQ/B,SAASkc,EAAEnjB,OAAO2P,aAAa,UACvC3F,EAAI0e,EAAK/pB,KAAO8pB,EAAK9pB,KAAOqK,EAAM,EAClCrF,EAAI+kB,EAAKnqB,IAAMkqB,EAAKlqB,IACpB2E,EAAQ5B,EAAQ,IAAMmjB,EAAKoG,WAC3BpU,EAAO,OAAST,EAAQ,IAAMkW,EAAU,GAAK,KAAOA,EAAU,KAE7D7K,IAAIwH,UAAU7e,EAAGrG,GAAI8S,KAAMA,EAAMvT,MAAOA,EAAOib,WAAY,SAC3DkD,IAAIyH,sEAOPzG,WAAWgC,YAAc,MAC1Bra,GAAI,EAEJ5H,EAASib,KAAK+B,aAAahd,QAAU,EAErC+pB,EAAW1gB,EAAS,iBAAkBzB,EA1K1BmhB,GA0KgC,iBAEpCA,MACN,MAGDiB,QACA/J,WAAWxa,YAAYskB,QAEvBtP,OAAO1Y,MAAM,EpB5GqB,GoB4GS+D,IAAI,SAACvB,EAAO1B,MACrDkiB,GAASpc,EAAW,sBAAuBf,EAAI,GAAkB/E,EApLxDkmB,GpByEiB,GoB4GP/oB,EAAQuE,KAC5B0b,WAAWxa,YAAYsf,QAIzBkF,GAAW5gB,EAAS,iBADRzB,EAAIsiB,GAA8CF,EAzLlDjB,GA0LwC,iBAE5CA,MACN,SAGD9I,WAAWxa,YAAYwkB,4CAaxB,GATAxI,GAAIxG,KAAK8C,SACoB0D,EAAEtiB,MAAMsT,WAAYgP,EAAEtiB,MAAMuT,eAAtDyX,OAAYC,UACU3I,EAAE7I,IAAInG,WAAYgP,EAAE7I,IAAIlG,eAE/C2X,OAAyBF,EAAa,EAA6B,SAAbC,GAExDd,KAEAgB,EAAehZ,GAAMmQ,EAAEtiB,OACnB0D,EAAI,EAAGA,EAAIwnB,EAAYxnB,IAAK,IAC/BgQ,GAAU4O,EAAE7I,QACZtF,GAAegX,EAAc7I,EAAE7I,KAAM,QACnB0R,EAAa7X,WAAY6X,EAAa5X,iBACjDiB,gBAEG7Q,KAAKmY,KAAKsP,gBAAgBD,EAAczX,OAE9CA,EAAS,KACFA,QAGTyW,2CAGQ1W,MAAWC,0DAAQ,MACbD,EAAUH,WAAYG,EAAUF,eAAhDkB,OAAOC,OACR2W,EAAczX,GAAeH,GAG7B6X,SACI7W,gBAHEtC,GAAMuB,IAAYc,GAAmBC,EAAOC,GAOrC,OAIb,GAHA6W,GAAiB/X,GAAgB6X,EAAa3X,GAE9C4R,KAAWhgB,SACP5B,EAAI,EAAGA,EAAI6nB,EAAgB7nB,MAC5BoY,KAAK0P,OAAOH,EAAa5W,KAC1B9Q,KAAK2B,QAEI,GAAIzD,MAAKyD,EAAIyO,GAAqB,GAAG2R,UAC9B,cAGuBpkB,KAA1CgE,EAAIyO,GAAqB,GAAG4R,eACtB0F,EAAa,KAChB1nB,KAAKmY,KAAK0P,OAAOH,EAAa5W,GAAO,OAG9B6Q,KAAOA,EAEbgG,iCAGD7X,EAAWgB,OAOb,GAPoBgX,2DACpBnJ,EAAIxG,KAAK8C,MAGT8M,EAAcvZ,GAAMsB,GACpBnO,KAEI5B,EAAI,EAAGA,EAAIqQ,GAAoBrQ,IAAKoR,GAAQ4W,EAAa,GAAI,IAChEhW,MAGAiW,EAAwBD,GAAepJ,EAAEtiB,OAAS0rB,GAAepJ,EAAE7I,GAEpEgS,IAASC,EAAYpY,aAAemB,IAAUkX,IACzCjG,SAAWxS,GAAYwY,KAErB5P,KAAK8P,mBAAmBF,KAE9B/nB,KAAK+R,SAGHpQ,8CAGWuN,MACd6S,GAAWxS,GAAYL,GACvB8S,EAAY7J,KAAKpS,KAAKsgB,WAAWtE,mBAE1BA,YACCC,GAAa,OAClB7J,KAAKR,OAAOvC,GAAiB4M,EAAW7J,KAAK8C,MAAM/F,uBAtRvB6E,ICFhBnD,0BACRhT,EAAQO,8EACbP,EAAQO,aAET+e,WAAa/e,EAAK+e,iBAClBgF,YAAc/jB,EAAK+jB,kBAEnBntB,KAAOoJ,EAAKpJ,MAAQ,SACpBuhB,KAAO,IAEPtE,mEAIFG,KAAKpS,KAAKyP,SAASlZ,QAAU,SAC1ByV,OAAO+I,WAAa,OACpBL,SAAS/e,SAAS3B,OAAS,sCAIxB0M,4FACOA,KAER0hB,YAAc1hB,EAAQ0hB,kBACtB3J,eAAiB/X,EAAQ+X,wBAE5BzM,OAAOqW,UAAY3hB,EAAQ0hB,YAAYC,WAAa,YACpDrW,OAAOsW,UAAY5hB,EAAQ0hB,YAAYE,WAAa,YACpDtW,OAAOuW,UAAY7hB,EAAQ0hB,YAAYG,WAAa,OACpDvW,OAAOwW,oBAAsB9hB,EAAQ0hB,YAAYI,qBAAuB,OAExExW,OAAOyW,eAAiB/hB,EAAQ+X,eAAegK,oBAC/CzW,OAAOwM,eAAiB9X,EAAQ+X,eAAeD,oBAE/CxM,OAAOgR,iBAAmBtc,EAAQsc,6DAIhC1N,2DADS8C,KAAKpS,KACCoS,KAAKpd,uDAIpBgb,2DADcoC,KAAKpS,wCAItBsW,gEACCoM,iBACDpM,QACEqM,oBAAoBvQ,KAAKwQ,gBAA+B,SAAdxQ,KAAKpd,WAEhD6tB,8DAIDjK,GAAIxG,KAAK8C,MACT3F,EAAS6C,KAAKpS,KAAKuP,SACrBC,cAAgBD,EAAOhZ,SAEvBusB,UAAY1Q,KAAKrU,MAAO6a,EAAEpJ,gBAE1BuT,QAAUnK,EAAEkK,UAAU,IAMtBE,cACOzT,YACGA,EAAOtS,IAAI,SAAChH,EAAG+D,SACzBhE,GAAS4iB,EAAEmK,QAAU/oB,EAAI4e,EAAEkK,0DAKVG,MACbjV,GAAOV,GAAmB2V,yDADa,SAEvCzU,EAAkB4D,KAAK3Z,OAAS4V,GAAcL,GAC9CkV,EAAiBhV,GAAgBF,GAAQQ,EACzChW,EAAW4Z,KAAK3Z,OAAUsV,GAAaC,GAAQkV,OAEhDhO,MAAM3G,cACFP,YACGA,EAAK/Q,IAAI,kBAAKzE,GAAWvC,EAAIuY,oBACvBA,WACPhW,QAIN2qB,yBACAC,qBACAC,8DAIDzK,GAAIxG,KAAK8C,MACToO,EAAW,kBAAU/V,GAAOtQ,IAAI,kBAAOqR,IAAM3R,EAAKic,EAAErK,YAEtDkB,SAAW2C,KAAKpS,KAAKyP,SAASxS,IAAI,SAAChH,EAAG+D,MACnCuT,GAAStX,EAAEsX,OACXgW,EAAettB,EAAEstB,6BAEdttB,EAAEuV,MAAQvV,EAAEuV,KAAKgY,QAAQ,SAAU,SAACC,SAAiB,KAARA,EAAc,QAAkB,KAARA,EAAc,OAAS,eAC3FzpB,YACI/D,EAAE2Z,iBAELrC,aACI+V,EAAS/V,gBAEPgW,iBACED,EAASC,iDAMvB3K,GAAIxG,KAAK8C,SACV9C,KAAK+K,WAAWuG,sBAChBC,UAAY/K,EAAEnJ,SAASmJ,EAAEnJ,SAASlZ,OAAS,GAAGqtB,kBAG/CD,UAAY,GAAIltB,OAAMmiB,EAAEpJ,eAAe5Y,KAAK,QAC5C6Y,SAASxS,IAAI,cACZof,WAAWpf,IAAI,SAACyE,EAAKrM,GACnBqM,EAAMkX,EAAE+K,UAAUtuB,OAClBsuB,UAAUtuB,GAAKqM,iDAOhBkX,GAAIxG,KAAK8C,KACV9C,MAAKpS,KAAKmQ,gBACP+E,MAAM/E,SAAWiC,KAAKpS,KAAKmQ,SAASlT,IAAI,qBAC1Cyd,SAAWpM,GAAMrY,EAAEgC,MAAO2gB,EAAErK,OAC1BtY,EAAEyK,UAASzK,EAAEyK,YAIVzK,KAGNmc,KAAKpS,KAAK8P,gBACPoF,MAAMpF,SAAWsC,KAAKpS,KAAK8P,SAAS7S,IAAI,qBAC1Cie,SAAW5M,GAAMrY,EAAEK,MAAOsiB,EAAErK,SAC5B4M,OAAS7M,GAAMrY,EAAE8Z,IAAK6I,EAAErK,OACtBtY,EAAEyK,UAASzK,EAAEyK,YACVzK,0DAMLiC,EAAM,YAEPka,KAAK+K,WAAWuG,QAAS,GACrB,kBACFG,GAAa,GAAIptB,OAAM2b,KAAK8C,MAAM1F,eAAe5Y,KAAK,QACrDoJ,KAAKyP,SAASxS,IAAI,SAAChH,EAAG+D,MACtBuT,GAASmF,EAAK1S,KAAKyP,SAASzV,GAAGuT,SACjCrV,GAAO2rB,EAAaA,EAAW5mB,IAAI,SAACqW,EAAGtZ,SAAMsZ,GAAI/F,EAAOvT,UAIxD8pB,GAAgB1R,KAAKpS,KAAKyP,SAASxS,IAAI,kBAAKhH,GAAEiC,WAC/Cka,MAAKpS,KAAKmQ,YACElW,KAAKmY,KAAKpS,KAAKmQ,SAASlT,IAAI,kBAAKhH,GAAEgC,SAE/Cma,KAAKpS,KAAK8P,eACP9P,KAAK8P,SAAS7S,IAAI,cACRhD,MAAMhE,EAAE8Z,IAAK9Z,EAAEK,iBAIrBO,kBAAUitB,yDAIhBlY,IAEF,cAEOwG,KAAKpG,OAAOsW,gBACXlQ,KAAKrU,qBACIqU,KAAKpG,OAAOwW,qBAG7B,iBACQpQ,MAAK8C,MAAM3G,OACjBsJ,KAAKzF,QAIP,cAEOA,KAAKpG,OAAOqW,iBACVjQ,KAAK3Z,QAGd,cACKmgB,GAAIxG,KAAK8C,eACX8N,MAAMjI,WAAa3K,GAAmBgC,KAAKrU,MAC5C6a,EAAEoK,MAAMzT,OAAQ6C,KAAKpG,OAAOuW,WAEtB3J,EAAEoK,OACRnL,KAAKzF,QAIP,kBAEQA,KAAKrU,UACP,SAEN,iBACQqU,MAAK8C,MAAMpF,UACjB+H,KAAKzF,QAIL2R,EAAc3R,KAAK8C,MAAMzF,SAAS5D,OAAO,kBAAqB,QAAhB5V,EAAE2Z,YAChDoU,EAAe5R,KAAK8C,MAAMzF,SAAS5D,OAAO,kBAAqB,SAAhB5V,EAAE2Z,YAEjDqU,EAAcF,EAAY9mB,IAAI,eAC7BmF,GAAQnM,EAAEmM,aAEb,YAAmBnM,EAAEmM,aAEbA,QACAoX,EAAK5H,OAAOxP,WACVoX,EAAK2D,WAAWuG,yBAGPlK,EAAKxN,OAAOgR,2BrB9KG,EqB+KtBxD,EAAK/gB,QAEjB,cACKmgB,GAAIxG,KAAK8C,MACTjf,EAAI2iB,EAAEnJ,SAASrN,GACfshB,EAAUtR,KAAK+K,WAAWuG,QAE1BQ,EAAa9R,KAAK+K,WAAW+G,YrBvLD,GqBwL5B3H,EAAY3D,EAAEkK,WAAa,EAAIoB,GAC/B5K,EAAWiD,GAAWmH,EAAU,EAAIK,EAAYxtB,QAEhD8jB,EAAazB,EAAEoK,MAAMvI,UAAUxd,IAAI,kBAAK8B,GAAIwd,EAAU,GACtDmH,OACUrJ,EAAWpd,IAAI,kBAAK3D,GAAIggB,EAAWlX,QAG7CmN,GAAS,GAAI9Y,OAAMmiB,EAAEpJ,eAAe5Y,KAAK,GAC1Cwb,MAAKpG,OAAOgR,qBACX0G,GAAWztB,EAAEmM,QAAUwW,EAAEnJ,SAASlZ,OAAS,EACpCN,EAAEstB,aAEFttB,EAAEsX,WAIT+O,GAAU,GAAI7lB,OAAMmiB,EAAEpJ,eAAe5Y,KAAK,SAC3C8sB,OACQztB,EAAEomB,WAAWpf,IAAI,SAACvE,EAAGrD,SAAMqD,GAAIzC,EAAE2tB,eAAevuB,kBAI9CglB,aACApkB,EAAEomB,mBACLC,SAED/M,WAEEqJ,EAAErK,MAAM/V,mBACP+jB,WACDjD,IAEVzB,KAAK2B,MAIL2K,EAAcH,EAAa/mB,IAAI,eAC9BmF,GAAQnM,EAAEmM,aAEb,aAAoBnM,EAAEmM,aAEdA,QACAoX,EAAK5H,OAAOxP,WACVoX,EAAKxW,iBACJwW,EAAK2I,YAAYrf,oBACf0W,EAAK2I,YAAYjf,kBACrBsW,EAAK2I,YAAYvf,gBACf4W,EAAK2I,YAAYpF,kBACjBvD,EAAK2I,YAAYrF,0BAGTtD,EAAKxN,OAAOgR,kBAE/B,cACKpE,GAAIxG,KAAK8C,MACTjf,EAAI2iB,EAAEnJ,SAASrN,GACfgiB,EAAUxL,EAAErK,MAAMkM,UAAU,GAAK7B,EAAErK,MAAM/V,SAC1CogB,EAAErK,MAAMkM,UAAU,GAAK7B,EAAErK,MAAM/V,2BAGrBogB,EAAEoK,MAAMvI,qBACRxkB,EAAEomB,kBAENpmB,EAAEsX,gBAEA6W,SACFhS,KAAK+P,YAAYkC,SrBxPI,IqB0P7BxM,KAAK2B,MAIL8K,IAEF,kBAEQlS,KAAKrU,UACP,SAEN,iBACQqU,MAAK8C,MAAM/E,UACjB0H,KAAKzF,UAIUxG,EAAiB/U,OAAOotB,EAAaE,EAAaG,MAEjEC,IAAa,WAAY,iBACxBC,2BAEA7N,WAAa,GAAIW,KAAI1L,EACxBC,OAAO,mBAAS0Y,EAAUzY,SAAS1N,EAAK,KAAOob,EAAKtE,MAAM9W,EAAK,MAC/DnB,IAAI,eACAmgB,GAAY7R,mBAAgBnN,WAC7BA,EAAK,GAAG0N,SAAS,cAAgB1N,EAAK,GAAG0N,SAAS,gBAC/C0Y,mBAAmBvqB,KAAKmjB,IAEtBhf,EAAK,GAAIgf,gEAKdqH,kBAED7L,GAAIxG,KAAK8C,MACTwP,EAAUtS,KAAKpG,OAAOyW,eACtBkC,EAAUvS,KAAKpG,OAAOwM,cACbI,GAAEoK,MAAMzT,OAEdtS,IAAI,SAAC7D,EAAOgJ,MACdmL,GAAS4K,EAAKjD,MAAMzF,SAASxS,IAAI,SAACwV,EAAKzY,MACtC/B,GAAQwa,EAAIlF,OAAOnL,gBAEfqQ,EAAIjH,WACJvT,OACDwa,EAAI4J,WAAWja,SACd+V,EAAKvG,OAAO5X,aACR2qB,EAAUA,EAAQ1sB,GAASA,OAInCwsB,YAAYriB,UACThJ,iBACSsrB,EAAUA,EAAQtrB,GAASA,OACrCwf,EAAEoK,MAAMvI,UAAUrY,UAChBmL,WACEqL,EAAE+K,UAAUvhB,4DAOnB4G,UAAUwJ,iBAAiB,YAAa,SAAC0F,MACzC1iB,GAAIwlB,EAAKtG,SACT5Z,EAAI5H,EAAU8nB,EAAKhS,WACnB4b,EAAO1M,EAAE+G,MAAQnkB,EAAEpH,KAAOkC,EAAcJ,GACxCqvB,EAAO3M,EAAEgH,MAAQpkB,EAAExH,GAEpBuxB,GAAO7J,EAAKviB,OAASlD,EAAaC,IACjCqvB,EAAQtvB,EAAaC,KACnBsvB,oBAAoBF,KAEpBxO,IAAI/D,wDAKQuS,MACfhM,GAAIxG,KAAK8C,SACT0D,EAAE+K,cAEFvhB,GAAQqM,GAAkBmW,EAAMhM,EAAEoK,MAAMvI,WAAW,MACnDrY,GAAS,EAAG,IACX2iB,GAAM3S,KAAKqS,YAAYriB,QAEtBgU,IAAIwH,UACRmH,EAAI1H,KAAOjL,KAAKgE,IAAI1Y,OAAOqB,EAC3BgmB,EAAIC,SAAW5S,KAAKgE,IAAI1Y,OAAOhF,GAC9B8S,KAAMuZ,EAAIE,eAAgBhtB,MAAO,IAClC8sB,EAAIxX,OACJnL,QAGIgU,IAAIyH,8DAKNjF,EAAIxG,KAAKpS,IACV4Y,GAAEnJ,SAASlZ,OAAS,SACjB6gB,WAAWgC,YAAc,KAC5B3J,SAASxS,IAAI,SAAChH,EAAG+D,MAId5G,GAAO6M,ErB3WqB,IqB6WpBjG,EACX,IrB9W+B,IqBgX/BohB,EAAKxJ,OAAO5X,GACZ/D,EAAEuV,KACF4P,EAAKpP,OAAOyI,mBACR2C,WAAWxa,YAAYxJ,0DAS3Bgf,KAAKmE,sBACFA,KAAO,EAGVnE,MAAK8S,oBACFA,cAAc3P,QAAQ,eACtBza,GAAIoB,EAAEwX,UACR5W,WAAW2K,YAAY3M,UAItBoqB,cAAgB9S,KAAKoS,mBAAmBvnB,IAAI,wBAEzCqW,EAAE6I,qBACCvkB,SACF0b,EAAE8I,aAIoBxkB,KAA5Bwa,KAAK8C,MAAMiQ,oBACRjQ,MAAMiQ,aAAe/S,KAAK8C,MAAM1F,cAAgB,QAIjD0V,cAAcjoB,IAAI,eAClBmoB,GAAcnvB,EAAEmmB,MAAMiJ,EAAKnQ,MAAMiQ,gBAEnCzR,QAAUF,GAAYvd,EAAEjB,MAAMowB,KAC3BxO,SAASha,YAAY3G,EAAEyd,yDAK1BtB,KAAK8S,oBACFA,cAAc3P,QAAQ,eACtBza,GAAIoB,EAAEwX,UACR5W,WAAW2K,YAAY3M,2DAMtB+C,OAAO2U,iBAAiB,cAAe,aACtCmB,sEAKD6Q,mBAAmBvnB,IAAI,cACzBmf,MAAMnf,IAAI,cACNuV,iBAAiB,QAAS,cAC1BpQ,GAAQiB,EAAKqB,aAAa,sBACzB4gB,oBAAoBljB,cAMvBgU,IAAIpN,UAAUwJ,iBAAiB,QAAS,cACxCpQ,GAAQmjB,EAAKnP,IAAIpN,UAAUtE,aAAa,sBACvC4gB,oBAAoBljB,6DAKrB8iB,cAAcjoB,IAAI,eAClBmoB,GAAcnvB,EAAEmmB,MAAMoJ,EAAKtQ,MAAMiQ,iBACvBlvB,EAAEjB,MAAMowB,EAAanvB,EAAEyd,sDAKjC4R,oBAAoBlT,KAAK8C,MAAMiQ,aAAe,+CAI9CG,oBAAoBlT,KAAK8C,MAAMiQ,aAAe,6CAGvC/iB,0DAAMgQ,KAAK8C,MAAMiQ,aACzBvM,EAAIxG,KAAK8C,mBAEL9S,QACAwW,EAAEoK,MAAMzT,OAAOnN,UACdwW,EAAEnJ,SAASxS,IAAI,kBAAKhH,GAAEsX,OAAOnL,kDAKnBA,MACfwW,GAAIxG,KAAK8C,SACLlZ,SAASoG,IACN,IAAGA,EAAQ,GACnBA,GAASwW,EAAEoK,MAAMzT,OAAOhZ,SAAQ6L,EAAQwW,EAAEoK,MAAMzT,OAAOhZ,OAAS,GAChE6L,IAAUwW,EAAEuM,iBACbA,aAAe/iB,IACZgQ,KAAKvU,OAAQ,cAAeuU,KAAKqT,sDAM1BrsB,EAAOssB,MAAetjB,0DAAMgQ,KAAK8C,MAAM1F,0GAChCpW,EAAOssB,EAAetjB,QACpCpC,KAAKuP,OAAOoW,OAAOvjB,EAAO,EAAGhJ,QAC7B4G,KAAKyP,SAASxS,IAAI,SAAChH,EAAG+D,KACxBuT,OAAOoY,OAAOvjB,EAAO,EAAGsjB,EAAc1rB,WAEpC8c,OAAO1E,KAAKpS,mDAGFoC,0DAAQgQ,KAAK8C,MAAM1F,cAAc,CAC5C4C,MAAKpS,KAAKuP,OAAOhZ,QAAU,mGAGT6L,QACjBpC,KAAKuP,OAAOoW,OAAOvjB,EAAO,QAC1BpC,KAAKyP,SAASxS,IAAI,cACpBsQ,OAAOoY,OAAOvjB,EAAO,UAEnB0U,OAAO1E,KAAKpS,6CAGJ0lB,MAAetjB,0DAAM,OAC7BpC,KAAKyP,SAASrN,GAAOmL,OAASmY,OAC9B5O,OAAO1E,KAAKpS,6CAKHyP,QACTzP,KAAKyP,SAASxS,IAAI,SAAChH,EAAG+D,GACvByV,EAASzV,OACTuT,OAASkC,EAASzV,WAGjB8c,OAAO1E,KAAKpS,aA5jBoBgU,ICFlB4R,0BACR/nB,EAAQO,8EACbP,EAAQO,aACTpJ,KAAO,UACPmgB,YAAc,IACdoB,KAAO,IAEPtE,+DAGI7T,4FACOA,QACX2f,UAAY3L,KAAK2L,UAAUlG,KAAKzF,WAChC4L,WAAa5L,KAAK4L,WAAWnG,KAAKzF,WAElC6L,WAAa7f,EAAK6f,YAAc,QAChCjS,OAAOkS,WAAa9f,EAAK8f,YAAc,OAEvCtf,UAAYR,EAAKQ,YAAa,OAC9Bsb,YAAc9b,EAAK8b,aAAe,qIAKnCtB,GAAIxG,KAAK8C,WACR/d,OACJib,KAAK3Z,OAAS2Z,KAAKrU,MAChBqU,KAAKzT,OAAOI,EAAIqT,KAAK8H,YAAc,EACnC9H,KAAKzT,OAAOjG,EAAI0Z,KAAK8H,YAAc,KAE/B/iB,GAAsBib,KAAtBjb,OAAQyH,EAAcwT,KAAdxT,UAEVuf,EAAuBvF,EAAEwF,uBAC7BnE,kBACAmE,uBACEC,GAAW,IAAMjM,KAAKpG,OAAOkS,aAE/BrF,YAAY5b,IAAI,SAAC8b,EAAO/e,MACnBkkB,GAAaG,EACbC,EAAmBvF,EAAQH,EAAEO,WtB0DZ,IsBzDjBta,EAAWyf,EAAkB,IAAM,EAAG,EACtCC,EAAY3f,GAAa0f,EAAkBA,EAC3CE,EAAWH,GAAsBE,EACjC9f,EAAgBxH,EAAmBinB,EAAY/mB,GAC/CuH,EAAczH,EAAmBunB,EAAUrnB,GAE3CsnB,EAAe/L,EAAK6D,MAAQ4H,EAAqBnkB,GAEnD0kB,SAASC,QACVjM,GAAK6D,QACIkI,EAAeA,EAAahgB,cAAgBA,IAC9CggB,EAAeA,EAAa/f,YAAcD,MAExCA,IACFC,MAEJkgB,GACe,MAApBN,EACGhf,EAAoBof,EAAUC,EAAQjM,EAAK/T,OAAQ+T,EAAKvb,OAAQub,EAAK9T,UAAWC,GAChFQ,EAAqBqf,EAAUC,EAAQjM,EAAK/T,OAAQ+T,EAAKvb,OAAQub,EAAK9T,UAAWC,KAEnFob,aAAahgB,KAAK2kB,KAClBR,iBAAiBnkB,0CAGX8e,QACAH,EAAEO,yCAGFoF,WAIJhI,KAAO,+CAIRqC,GAAIxG,KAAK8C,MAETtJ,IAEF,iBAEA,+BAEgBgN,EAAEqB,oBACR7H,KAAKR,mBACAQ,KAAK8H,cAElBrC,KAAKzF,aAIJuE,WAAa,GAAIW,KAAI1L,EACxB3O,IAAI,eACAmgB,GAAY7R,mBAAgBnN,WACxBA,EAAK,GAAIgf,kDAIAyB,MACZ1nB,GAAuBib,KAAvBjb,OAAQ8mB,EAAe7L,KAAf6L,WACTvD,EAAWzjB,EAAmB4nB,EAASX,WAAYW,EAAS3nB,MAAQ,EAAGC,wBACtDujB,EAAS3b,EAAKkf,QAAiBvD,EAAShiB,EAAKulB,6CAG1Dpb,EAAK7I,EAAE8kB,EAAK5G,MAClBrV,MACEnH,GAAQ0W,KAAKR,OAAO5X,MACvB8kB,EAAM,IACEjc,EAAMuP,KAAK2M,oBAAoB3M,KAAK8C,MAAMkJ,iBAAiBpkB,OAChEkD,MAAM+D,OAASxF,EAAmBC,EAAO,OAC1CsjB,GAAQ9rB,EAAUkf,KAAK5J,KACvBzJ,EAAImZ,EAAE+G,MAAQD,EAAMtrB,KAAO,GAC3BgF,EAAIwf,EAAEgH,MAAQF,EAAM1rB,IAAM,GAC1Bgf,GAASF,KAAK+M,kBAAoB/M,KAAK+M,iBAAiB5oB,OAAS,EAClE6b,KAAK+M,iBAAiBnlB,GAAKoY,KAAK8C,MAAM3F,OAAOvV,IAAM,KAClDolB,GAAuC,IAA5BhN,KAAK8C,MAAM2D,YAAY7e,GAAWoY,KAAK8C,MAAMiE,YAAYjjB,QAAQ,QAC3EkgB,IAAIwH,UAAU7e,EAAGrG,GAAI8S,KAAM8G,EAAOra,MAAOmnB,EAAU,WACnDhJ,IAAIyH,kBAEChb,EAAK,2BACVuT,IAAI/D,YACJnV,MAAM+D,OAASvF,8CAKhBsN,UAAUwJ,iBAAiB,YAAaJ,KAAK2L,gBAC7C/U,UAAUwJ,iBAAiB,aAAcJ,KAAK4L,8CAG1C9F,MACHnjB,GAASmjB,EAAEnjB,OACbsqB,EAASjN,KAAKuE,WAAW4G,IAAI,eAAezD,MAC5CwF,EAAYlN,KAAKmN,oBACjBC,EAAapN,KAAKqN,kBACnBJ,EAAOvT,SAAS/W,GAAS,IACvBiF,GAAIqlB,EAAOlR,QAAQpZ,QAClB2qB,WAAWF,EAAYF,GAAU,QACjCG,eAAiB1qB,OACjBwqB,oBAAsBvlB,OACtB0lB,WAAW3qB,EAAQiF,GAAG,EAAMke,aAE5B8F,uDAKD0B,WAAWtN,KAAKqN,eAAerN,KAAKmN,qBAAoB,UArJvBhH,IVAlCzH,QACAD,QACCA,cAEMqM,WACHyC,OACJ7B,SACE8H,IAiBFC,GACL,WAAYhoB,EAAQ6C,qBACZkQ,GAAelQ,EAAQ1L,KAAM6I,EAAQ6C,wFWjC1ColB,YAEJA,IAAOC,KAAU,gBACjBD,GAAOE,QAAU,QAEjBF,GAAiBna,OAAOM,UAAY6Z,GAAQG"} \ No newline at end of file diff --git a/node_modules/frappe-charts/package.json b/node_modules/frappe-charts/package.json deleted file mode 100644 index 016170f..0000000 --- a/node_modules/frappe-charts/package.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "name": "frappe-charts", - "version": "1.6.2", - "description": "https://frappe.github.io/charts", - "main": "dist/frappe-charts.min.cjs.js", - "module": "dist/frappe-charts.min.esm.js", - "src": "dist/frappe-charts.esm.js", - "browser": "dist/frappe-charts.min.umd.js", - "directories": { - "doc": "docs" - }, - "files": [ - "src", - "dist" - ], - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "watch": "rollup -c --watch", - "dev": "npm-run-all --parallel watch", - "build": "rollup -c" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/frappe/charts.git" - }, - "keywords": [ - "js", - "charts" - ], - "author": "Prateeksha Singh", - "license": "MIT", - "bugs": { - "url": "https://github.com/frappe/charts/issues" - }, - "homepage": "https://github.com/frappe/charts#readme", - "devDependencies": { - "autoprefixer": "^8.2.0", - "babel-core": "^6.26.3", - "babel-plugin-external-helpers": "^6.22.0", - "babel-plugin-istanbul": "^5.1.4", - "babel-preset-env": "^1.7.0", - "babel-preset-latest": "^6.24.1", - "babel-register": "^6.26.0", - "clean-css": "^4.1.11", - "coveralls": "^3.0.0", - "cross-env": "^5.1.4", - "cssnano": "^4.1.10", - "eslint": "^4.18.2", - "mocha": "^5.0.5", - "node-sass": "^4.12.0", - "npm-run-all": "^4.1.1", - "nyc": "^14.1.1", - "postcss": "^6.0.21", - "postcss-cssnext": "^3.0.2", - "postcss-nested": "^2.1.2", - "precss": "^3.1.2", - "rollup": "^0.50.0", - "rollup-plugin-babel": "^3.0.2", - "rollup-plugin-eslint": "^6.0.0", - "rollup-plugin-node-resolve": "^3.0.0", - "rollup-plugin-postcss": "^2.0.3", - "rollup-plugin-replace": "^2.0.0", - "rollup-plugin-uglify": "^2.0.1", - "rollup-plugin-uglify-es": "0.0.1", - "rollup-watch": "^4.3.1" - }, - "dependencies": {} -} diff --git a/node_modules/frappe-charts/src/css/charts.scss b/node_modules/frappe-charts/src/css/charts.scss deleted file mode 100644 index d128335..0000000 --- a/node_modules/frappe-charts/src/css/charts.scss +++ /dev/null @@ -1,116 +0,0 @@ -.chart-container { - position: relative; /* for absolutely positioned tooltip */ - - /* https://www.smashingmagazine.com/2015/11/using-system-ui-fonts-practical-guide/ */ - font-family: -apple-system, BlinkMacSystemFont, - 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', - 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; - - .axis, .chart-label { - fill: #555b51; - - line { - stroke: #dadada; - } - } - .dataset-units { - circle { - stroke: #fff; - stroke-width: 2; - } - - path { - fill: none; - stroke-opacity: 1; - stroke-width: 2px; - } - } - .dataset-path { - stroke-width: 2px; - } - .path-group { - path { - fill: none; - stroke-opacity: 1; - stroke-width: 2px; - } - } - line.dashed { - stroke-dasharray: 5, 3; - } - .axis-line { - .specific-value { - text-anchor: start; - } - .y-line { - text-anchor: end; - } - .x-line { - text-anchor: middle; - } - } - .legend-dataset-text { - fill: #6c7680; - font-weight: 600; - } -} - -.graph-svg-tip { - position: absolute; - z-index: 99999; - padding: 10px; - font-size: 12px; - color: #959da5; - text-align: center; - background: rgba(0, 0, 0, 0.8); - border-radius: 3px; - ul { - padding-left: 0; - display: flex; - } - ol { - padding-left: 0; - display: flex; - } - ul.data-point-list { - li { - min-width: 90px; - flex: 1; - font-weight: 600; - } - } - strong { - color: #dfe2e5; - font-weight: 600; - } - .svg-pointer { - position: absolute; - height: 5px; - margin: 0 0 0 -5px; - content: ' '; - border: 5px solid transparent; - border-top-color: rgba(0, 0, 0, 0.8); - } - &.comparison { - padding: 0; - text-align: left; - pointer-events: none; - .title { - display: block; - padding: 10px; - margin: 0; - font-weight: 600; - line-height: 1; - pointer-events: none; - } - ul { - margin: 0; - white-space: nowrap; - list-style: none; - } - li { - display: inline-block; - padding: 5px 10px; - } - } -} diff --git a/node_modules/frappe-charts/src/css/chartsCss.js b/node_modules/frappe-charts/src/css/chartsCss.js deleted file mode 100644 index 71aa321..0000000 --- a/node_modules/frappe-charts/src/css/chartsCss.js +++ /dev/null @@ -1 +0,0 @@ -export const CSSTEXT = ".chart-container{position:relative;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI','Roboto','Oxygen','Ubuntu','Cantarell','Fira Sans','Droid Sans','Helvetica Neue',sans-serif}.chart-container .axis,.chart-container .chart-label{fill:#555b51}.chart-container .axis line,.chart-container .chart-label line{stroke:#dadada}.chart-container .dataset-units circle{stroke:#fff;stroke-width:2}.chart-container .dataset-units path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container .dataset-path{stroke-width:2px}.chart-container .path-group path{fill:none;stroke-opacity:1;stroke-width:2px}.chart-container line.dashed{stroke-dasharray:5,3}.chart-container .axis-line .specific-value{text-anchor:start}.chart-container .axis-line .y-line{text-anchor:end}.chart-container .axis-line .x-line{text-anchor:middle}.chart-container .legend-dataset-text{fill:#6c7680;font-weight:600}.graph-svg-tip{position:absolute;z-index:99999;padding:10px;font-size:12px;color:#959da5;text-align:center;background:rgba(0,0,0,.8);border-radius:3px}.graph-svg-tip ul{padding-left:0;display:flex}.graph-svg-tip ol{padding-left:0;display:flex}.graph-svg-tip ul.data-point-list li{min-width:90px;flex:1;font-weight:600}.graph-svg-tip strong{color:#dfe2e5;font-weight:600}.graph-svg-tip .svg-pointer{position:absolute;height:5px;margin:0 0 0 -5px;content:' ';border:5px solid transparent;border-top-color:rgba(0,0,0,.8)}.graph-svg-tip.comparison{padding:0;text-align:left;pointer-events:none}.graph-svg-tip.comparison .title{display:block;padding:10px;margin:0;font-weight:600;line-height:1;pointer-events:none}.graph-svg-tip.comparison ul{margin:0;white-space:nowrap;list-style:none}.graph-svg-tip.comparison li{display:inline-block;padding:5px 10px}"; \ No newline at end of file diff --git a/node_modules/frappe-charts/src/js/chart.js b/node_modules/frappe-charts/src/js/chart.js deleted file mode 100644 index 6606de3..0000000 --- a/node_modules/frappe-charts/src/js/chart.js +++ /dev/null @@ -1,40 +0,0 @@ -import '../css/charts.scss'; - -// import MultiAxisChart from './charts/MultiAxisChart'; -import PercentageChart from './charts/PercentageChart'; -import PieChart from './charts/PieChart'; -import Heatmap from './charts/Heatmap'; -import AxisChart from './charts/AxisChart'; -import DonutChart from './charts/DonutChart'; - -const chartTypes = { - bar: AxisChart, - line: AxisChart, - // multiaxis: MultiAxisChart, - percentage: PercentageChart, - heatmap: Heatmap, - pie: PieChart, - donut: DonutChart, -}; - -function getChartByType(chartType = 'line', parent, options) { - if (chartType === 'axis-mixed') { - options.type = 'line'; - return new AxisChart(parent, options); - } - - if (!chartTypes[chartType]) { - console.error("Undefined chart type: " + chartType); - return; - } - - return new chartTypes[chartType](parent, options); -} - -class Chart { - constructor(parent, options) { - return getChartByType(options.type, parent, options); - } -} - -export { Chart, PercentageChart, PieChart, Heatmap, AxisChart }; \ No newline at end of file diff --git a/node_modules/frappe-charts/src/js/charts/AggregationChart.js b/node_modules/frappe-charts/src/js/charts/AggregationChart.js deleted file mode 100644 index 2e6f79f..0000000 --- a/node_modules/frappe-charts/src/js/charts/AggregationChart.js +++ /dev/null @@ -1,95 +0,0 @@ -import BaseChart from './BaseChart'; -import { truncateString } from '../utils/draw-utils'; -import { legendDot } from '../utils/draw'; -import { round } from '../utils/helpers'; -import { getExtraWidth } from '../utils/constants'; - -export default class AggregationChart extends BaseChart { - constructor(parent, args) { - super(parent, args); - } - - configure(args) { - super.configure(args); - - this.config.formatTooltipY = (args.tooltipOptions || {}).formatTooltipY; - this.config.maxSlices = args.maxSlices || 20; - this.config.maxLegendPoints = args.maxLegendPoints || 20; - } - - calc() { - let s = this.state; - let maxSlices = this.config.maxSlices; - s.sliceTotals = []; - - let allTotals = this.data.labels.map((label, i) => { - let total = 0; - this.data.datasets.map(e => { - total += e.values[i]; - }); - return [total, label]; - }).filter(d => { return d[0] >= 0; }); // keep only positive results - - let totals = allTotals; - if(allTotals.length > maxSlices) { - // Prune and keep a grey area for rest as per maxSlices - allTotals.sort((a, b) => { return b[0] - a[0]; }); - - totals = allTotals.slice(0, maxSlices-1); - let remaining = allTotals.slice(maxSlices-1); - - let sumOfRemaining = 0; - remaining.map(d => {sumOfRemaining += d[0];}); - totals.push([sumOfRemaining, 'Rest']); - this.colors[maxSlices-1] = 'grey'; - } - - s.labels = []; - totals.map(d => { - s.sliceTotals.push(round(d[0])); - s.labels.push(d[1]); - }); - - s.grandTotal = s.sliceTotals.reduce((a, b) => a + b, 0); - - this.center = { - x: this.width / 2, - y: this.height / 2 - }; - } - - renderLegend() { - let s = this.state; - this.legendArea.textContent = ''; - this.legendTotals = s.sliceTotals.slice(0, this.config.maxLegendPoints); - - let count = 0; - let y = 0; - this.legendTotals.map((d, i) => { - let barWidth = 150; - let divisor = Math.floor( - (this.width - getExtraWidth(this.measures))/barWidth - ); - if (this.legendTotals.length < divisor) { - barWidth = this.width/this.legendTotals.length; - } - if(count > divisor) { - count = 0; - y += 20; - } - let x = barWidth * count + 5; - let label = this.config.truncateLegends ? truncateString(s.labels[i], barWidth/10) : s.labels[i]; - let formatted = this.config.formatTooltipY ? this.config.formatTooltipY(d) : d; - let dot = legendDot( - x, - y, - 5, - this.colors[i], - `${label}: ${formatted}`, - false - ); - this.legendArea.appendChild(dot); - count++; - }); - } -} diff --git a/node_modules/frappe-charts/src/js/charts/AxisChart.js b/node_modules/frappe-charts/src/js/charts/AxisChart.js deleted file mode 100644 index 9c06bbd..0000000 --- a/node_modules/frappe-charts/src/js/charts/AxisChart.js +++ /dev/null @@ -1,590 +0,0 @@ -import BaseChart from './BaseChart'; -import { dataPrep, zeroDataPrep, getShortenedLabels } from '../utils/axis-chart-utils'; -import { AXIS_LEGEND_BAR_SIZE } from '../utils/constants'; -import { getComponent } from '../objects/ChartComponents'; -import { getOffset, fire } from '../utils/dom'; -import { calcChartIntervals, getIntervalSize, getValueRange, getZeroIndex, scale, getClosestInArray } from '../utils/intervals'; -import { floatTwo } from '../utils/helpers'; -import { makeOverlay, updateOverlay, legendBar } from '../utils/draw'; -import { getTopOffset, getLeftOffset, MIN_BAR_PERCENT_HEIGHT, BAR_CHART_SPACE_RATIO, - LINE_CHART_DOT_SIZE } from '../utils/constants'; - -export default class AxisChart extends BaseChart { - constructor(parent, args) { - super(parent, args); - - this.barOptions = args.barOptions || {}; - this.lineOptions = args.lineOptions || {}; - - this.type = args.type || 'line'; - this.init = 1; - - this.setup(); - } - - setMeasures() { - if(this.data.datasets.length <= 1) { - this.config.showLegend = 0; - this.measures.paddings.bottom = 30; - } - } - - configure(options) { - super.configure(options); - - options.axisOptions = options.axisOptions || {}; - options.tooltipOptions = options.tooltipOptions || {}; - - this.config.xAxisMode = options.axisOptions.xAxisMode || 'span'; - this.config.yAxisMode = options.axisOptions.yAxisMode || 'span'; - this.config.xIsSeries = options.axisOptions.xIsSeries || 0; - this.config.shortenYAxisNumbers = options.axisOptions.shortenYAxisNumbers || 0; - - this.config.formatTooltipX = options.tooltipOptions.formatTooltipX; - this.config.formatTooltipY = options.tooltipOptions.formatTooltipY; - - this.config.valuesOverPoints = options.valuesOverPoints; - } - - prepareData(data=this.data) { - return dataPrep(data, this.type); - } - - prepareFirstData(data=this.data) { - return zeroDataPrep(data); - } - - calc(onlyWidthChange = false) { - this.calcXPositions(); - if(!onlyWidthChange) { - this.calcYAxisParameters(this.getAllYValues(), this.type === 'line'); - } - this.makeDataByIndex(); - } - - calcXPositions() { - let s = this.state; - let labels = this.data.labels; - s.datasetLength = labels.length; - - s.unitWidth = this.width/(s.datasetLength); - // Default, as per bar, and mixed. Only line will be a special case - s.xOffset = s.unitWidth/2; - - // // For a pure Line Chart - // s.unitWidth = this.width/(s.datasetLength - 1); - // s.xOffset = 0; - - s.xAxis = { - labels: labels, - positions: labels.map((d, i) => - floatTwo(s.xOffset + i * s.unitWidth) - ) - }; - } - - calcYAxisParameters(dataValues, withMinimum = 'false') { - const yPts = calcChartIntervals(dataValues, withMinimum); - const scaleMultiplier = this.height / getValueRange(yPts); - const intervalHeight = getIntervalSize(yPts) * scaleMultiplier; - const zeroLine = this.height - (getZeroIndex(yPts) * intervalHeight); - - this.state.yAxis = { - labels: yPts, - positions: yPts.map(d => zeroLine - d * scaleMultiplier), - scaleMultiplier: scaleMultiplier, - zeroLine: zeroLine, - }; - - // Dependent if above changes - this.calcDatasetPoints(); - this.calcYExtremes(); - this.calcYRegions(); - } - - calcDatasetPoints() { - let s = this.state; - let scaleAll = values => values.map(val => scale(val, s.yAxis)); - - s.datasets = this.data.datasets.map((d, i) => { - let values = d.values; - let cumulativeYs = d.cumulativeYs || []; - return { - name: d.name && d.name.replace(/<|>|&/g, (char) => char == '&' ? '&' : char == '<' ? '<' : '>'), - index: i, - chartType: d.chartType, - - values: values, - yPositions: scaleAll(values), - - cumulativeYs: cumulativeYs, - cumulativeYPos: scaleAll(cumulativeYs), - }; - }); - } - - calcYExtremes() { - let s = this.state; - if(this.barOptions.stacked) { - s.yExtremes = s.datasets[s.datasets.length - 1].cumulativeYPos; - return; - } - s.yExtremes = new Array(s.datasetLength).fill(9999); - s.datasets.map(d => { - d.yPositions.map((pos, j) => { - if(pos < s.yExtremes[j]) { - s.yExtremes[j] = pos; - } - }); - }); - } - - calcYRegions() { - let s = this.state; - if(this.data.yMarkers) { - this.state.yMarkers = this.data.yMarkers.map(d => { - d.position = scale(d.value, s.yAxis); - if(!d.options) d.options = {}; - // if(!d.label.includes(':')) { - // d.label += ': ' + d.value; - // } - return d; - }); - } - if(this.data.yRegions) { - this.state.yRegions = this.data.yRegions.map(d => { - d.startPos = scale(d.start, s.yAxis); - d.endPos = scale(d.end, s.yAxis); - if(!d.options) d.options = {}; - return d; - }); - } - } - - getAllYValues() { - let key = 'values'; - - if(this.barOptions.stacked) { - key = 'cumulativeYs'; - let cumulative = new Array(this.state.datasetLength).fill(0); - this.data.datasets.map((d, i) => { - let values = this.data.datasets[i].values; - d[key] = cumulative = cumulative.map((c, i) => c + values[i]); - }); - } - - let allValueLists = this.data.datasets.map(d => d[key]); - if(this.data.yMarkers) { - allValueLists.push(this.data.yMarkers.map(d => d.value)); - } - if(this.data.yRegions) { - this.data.yRegions.map(d => { - allValueLists.push([d.end, d.start]); - }); - } - - return [].concat(...allValueLists); - } - - setupComponents() { - let componentConfigs = [ - [ - 'yAxis', - { - mode: this.config.yAxisMode, - width: this.width, - shortenNumbers: this.config.shortenYAxisNumbers - // pos: 'right' - }, - function() { - return this.state.yAxis; - }.bind(this) - ], - - [ - 'xAxis', - { - mode: this.config.xAxisMode, - height: this.height, - // pos: 'right' - }, - function() { - let s = this.state; - s.xAxis.calcLabels = getShortenedLabels(this.width, - s.xAxis.labels, this.config.xIsSeries); - - return s.xAxis; - }.bind(this) - ], - - [ - 'yRegions', - { - width: this.width, - pos: 'right' - }, - function() { - return this.state.yRegions; - }.bind(this) - ], - ]; - - let barDatasets = this.state.datasets.filter(d => d.chartType === 'bar'); - let lineDatasets = this.state.datasets.filter(d => d.chartType === 'line'); - - let barsConfigs = barDatasets.map(d => { - let index = d.index; - return [ - 'barGraph' + '-' + d.index, - { - index: index, - color: this.colors[index], - stacked: this.barOptions.stacked, - - // same for all datasets - valuesOverPoints: this.config.valuesOverPoints, - minHeight: this.height * MIN_BAR_PERCENT_HEIGHT, - }, - function() { - let s = this.state; - let d = s.datasets[index]; - let stacked = this.barOptions.stacked; - - let spaceRatio = this.barOptions.spaceRatio || BAR_CHART_SPACE_RATIO; - let barsWidth = s.unitWidth * (1 - spaceRatio); - let barWidth = barsWidth/(stacked ? 1 : barDatasets.length); - - let xPositions = s.xAxis.positions.map(x => x - barsWidth/2); - if(!stacked) { - xPositions = xPositions.map(p => p + barWidth * index); - } - - let labels = new Array(s.datasetLength).fill(''); - if(this.config.valuesOverPoints) { - if(stacked && d.index === s.datasets.length - 1) { - labels = d.cumulativeYs; - } else { - labels = d.values; - } - } - - let offsets = new Array(s.datasetLength).fill(0); - if(stacked) { - offsets = d.yPositions.map((y, j) => y - d.cumulativeYPos[j]); - } - - return { - xPositions: xPositions, - yPositions: d.yPositions, - offsets: offsets, - // values: d.values, - labels: labels, - - zeroLine: s.yAxis.zeroLine, - barsWidth: barsWidth, - barWidth: barWidth, - }; - }.bind(this) - ]; - }); - - let lineConfigs = lineDatasets.map(d => { - let index = d.index; - return [ - 'lineGraph' + '-' + d.index, - { - index: index, - color: this.colors[index], - svgDefs: this.svgDefs, - heatline: this.lineOptions.heatline, - regionFill: this.lineOptions.regionFill, - spline: this.lineOptions.spline, - hideDots: this.lineOptions.hideDots, - hideLine: this.lineOptions.hideLine, - - // same for all datasets - valuesOverPoints: this.config.valuesOverPoints, - }, - function() { - let s = this.state; - let d = s.datasets[index]; - let minLine = s.yAxis.positions[0] < s.yAxis.zeroLine - ? s.yAxis.positions[0] : s.yAxis.zeroLine; - - return { - xPositions: s.xAxis.positions, - yPositions: d.yPositions, - - values: d.values, - - zeroLine: minLine, - radius: this.lineOptions.dotSize || LINE_CHART_DOT_SIZE, - }; - }.bind(this) - ]; - }); - - let markerConfigs = [ - [ - 'yMarkers', - { - width: this.width, - pos: 'right' - }, - function() { - return this.state.yMarkers; - }.bind(this) - ] - ]; - - componentConfigs = componentConfigs.concat(barsConfigs, lineConfigs, markerConfigs); - - let optionals = ['yMarkers', 'yRegions']; - this.dataUnitComponents = []; - - this.components = new Map(componentConfigs - .filter(args => !optionals.includes(args[0]) || this.state[args[0]]) - .map(args => { - let component = getComponent(...args); - if(args[0].includes('lineGraph') || args[0].includes('barGraph')) { - this.dataUnitComponents.push(component); - } - return [args[0], component]; - })); - } - - makeDataByIndex() { - this.dataByIndex = {}; - - let s = this.state; - let formatX = this.config.formatTooltipX; - let formatY = this.config.formatTooltipY; - let titles = s.xAxis.labels; - - titles.map((label, index) => { - let values = this.state.datasets.map((set, i) => { - let value = set.values[index]; - return { - title: set.name, - value: value, - yPos: set.yPositions[index], - color: this.colors[i], - formatted: formatY ? formatY(value) : value, - }; - }); - - this.dataByIndex[index] = { - label: label, - formattedLabel: formatX ? formatX(label) : label, - xPos: s.xAxis.positions[index], - values: values, - yExtreme: s.yExtremes[index], - }; - }); - } - - bindTooltip() { - // NOTE: could be in tooltip itself, as it is a given functionality for its parent - this.container.addEventListener('mousemove', (e) => { - let m = this.measures; - let o = getOffset(this.container); - let relX = e.pageX - o.left - getLeftOffset(m); - let relY = e.pageY - o.top; - - if(relY < this.height + getTopOffset(m) - && relY > getTopOffset(m)) { - this.mapTooltipXPosition(relX); - } else { - this.tip.hideTip(); - } - }); - } - - mapTooltipXPosition(relX) { - let s = this.state; - if(!s.yExtremes) return; - - let index = getClosestInArray(relX, s.xAxis.positions, true); - if (index >= 0) { - let dbi = this.dataByIndex[index]; - - this.tip.setValues( - dbi.xPos + this.tip.offset.x, - dbi.yExtreme + this.tip.offset.y, - {name: dbi.formattedLabel, value: ''}, - dbi.values, - index - ); - - this.tip.showTip(); - } - } - - renderLegend() { - let s = this.data; - if(s.datasets.length > 1) { - this.legendArea.textContent = ''; - s.datasets.map((d, i) => { - let barWidth = AXIS_LEGEND_BAR_SIZE; - // let rightEndPoint = this.baseWidth - this.measures.margins.left - this.measures.margins.right; - // let multiplier = s.datasets.length - i; - let rect = legendBar( - // rightEndPoint - multiplier * barWidth, // To right align - barWidth * i, - '0', - barWidth, - this.colors[i], - d.name, - this.config.truncateLegends); - this.legendArea.appendChild(rect); - }); - } - } - - - - // Overlay - makeOverlay() { - if(this.init) { - this.init = 0; - return; - } - if(this.overlayGuides) { - this.overlayGuides.forEach(g => { - let o = g.overlay; - o.parentNode.removeChild(o); - }); - } - - this.overlayGuides = this.dataUnitComponents.map(c => { - return { - type: c.unitType, - overlay: undefined, - units: c.units, - }; - }); - - if(this.state.currentIndex === undefined) { - this.state.currentIndex = this.state.datasetLength - 1; - } - - // Render overlays - this.overlayGuides.map(d => { - let currentUnit = d.units[this.state.currentIndex]; - - d.overlay = makeOverlay[d.type](currentUnit); - this.drawArea.appendChild(d.overlay); - }); - } - - updateOverlayGuides() { - if(this.overlayGuides) { - this.overlayGuides.forEach(g => { - let o = g.overlay; - o.parentNode.removeChild(o); - }); - } - } - - bindOverlay() { - this.parent.addEventListener('data-select', () => { - this.updateOverlay(); - }); - } - - bindUnits() { - this.dataUnitComponents.map(c => { - c.units.map(unit => { - unit.addEventListener('click', () => { - let index = unit.getAttribute('data-point-index'); - this.setCurrentDataPoint(index); - }); - }); - }); - - // Note: Doesn't work as tooltip is absolutely positioned - this.tip.container.addEventListener('click', () => { - let index = this.tip.container.getAttribute('data-point-index'); - this.setCurrentDataPoint(index); - }); - } - - updateOverlay() { - this.overlayGuides.map(d => { - let currentUnit = d.units[this.state.currentIndex]; - updateOverlay[d.type](currentUnit, d.overlay); - }); - } - - onLeftArrow() { - this.setCurrentDataPoint(this.state.currentIndex - 1); - } - - onRightArrow() { - this.setCurrentDataPoint(this.state.currentIndex + 1); - } - - getDataPoint(index=this.state.currentIndex) { - let s = this.state; - let data_point = { - index: index, - label: s.xAxis.labels[index], - values: s.datasets.map(d => d.values[index]) - }; - return data_point; - } - - setCurrentDataPoint(index) { - let s = this.state; - index = parseInt(index); - if(index < 0) index = 0; - if(index >= s.xAxis.labels.length) index = s.xAxis.labels.length - 1; - if(index === s.currentIndex) return; - s.currentIndex = index; - fire(this.parent, "data-select", this.getDataPoint()); - } - - - - // API - addDataPoint(label, datasetValues, index=this.state.datasetLength) { - super.addDataPoint(label, datasetValues, index); - this.data.labels.splice(index, 0, label); - this.data.datasets.map((d, i) => { - d.values.splice(index, 0, datasetValues[i]); - }); - this.update(this.data); - } - - removeDataPoint(index = this.state.datasetLength-1) { - if (this.data.labels.length <= 1) { - return; - } - super.removeDataPoint(index); - this.data.labels.splice(index, 1); - this.data.datasets.map(d => { - d.values.splice(index, 1); - }); - this.update(this.data); - } - - updateDataset(datasetValues, index=0) { - this.data.datasets[index].values = datasetValues; - this.update(this.data); - } - // addDataset(dataset, index) {} - // removeDataset(index = 0) {} - - updateDatasets(datasets) { - this.data.datasets.map((d, i) => { - if(datasets[i]) { - d.values = datasets[i]; - } - }); - this.update(this.data); - } - - // updateDataPoint(dataPoint, index = 0) {} - // addDataPoint(dataPoint, index = 0) {} - // removeDataPoint(index = 0) {} -} diff --git a/node_modules/frappe-charts/src/js/charts/BaseChart.js b/node_modules/frappe-charts/src/js/charts/BaseChart.js deleted file mode 100644 index 3cc5695..0000000 --- a/node_modules/frappe-charts/src/js/charts/BaseChart.js +++ /dev/null @@ -1,324 +0,0 @@ -import SvgTip from '../objects/SvgTip'; -import { $, isElementInViewport, getElementContentWidth, isHidden } from '../utils/dom'; -import { makeSVGContainer, makeSVGDefs, makeSVGGroup, makeText } from '../utils/draw'; -import { BASE_MEASURES, getExtraHeight, getExtraWidth, getTopOffset, getLeftOffset, - INIT_CHART_UPDATE_TIMEOUT, CHART_POST_ANIMATE_TIMEOUT, DEFAULT_COLORS} from '../utils/constants'; -import { getColor, isValidColor } from '../utils/colors'; -import { runSMILAnimation } from '../utils/animation'; -import { downloadFile, prepareForExport } from '../utils/export'; -import { deepClone } from '../utils/helpers'; - -export default class BaseChart { - constructor(parent, options) { - // deepclone options to avoid making changes to orignal object - options = deepClone(options); - - this.parent = typeof parent === 'string' - ? document.querySelector(parent) - : parent; - - if (!(this.parent instanceof HTMLElement)) { - throw new Error('No `parent` element to render on was provided.'); - } - - this.rawChartArgs = options; - - this.title = options.title || ''; - this.type = options.type || ''; - - this.realData = this.prepareData(options.data); - this.data = this.prepareFirstData(this.realData); - - this.colors = this.validateColors(options.colors, this.type); - - this.config = { - showTooltip: 1, // calculate - showLegend: 1, // calculate - isNavigable: options.isNavigable || 0, - animate: (typeof options.animate !== 'undefined') ? options.animate : 1, - truncateLegends: options.truncateLegends || 1 - }; - - this.measures = JSON.parse(JSON.stringify(BASE_MEASURES)); - let m = this.measures; - this.setMeasures(options); - if(!this.title.length) { m.titleHeight = 0; } - if(!this.config.showLegend) m.legendHeight = 0; - this.argHeight = options.height || m.baseHeight; - - this.state = {}; - this.options = {}; - - this.initTimeout = INIT_CHART_UPDATE_TIMEOUT; - - if(this.config.isNavigable) { - this.overlays = []; - } - - this.configure(options); - } - - prepareData(data) { - return data; - } - - prepareFirstData(data) { - return data; - } - - validateColors(colors, type) { - const validColors = []; - colors = (colors || []).concat(DEFAULT_COLORS[type]); - colors.forEach((string) => { - const color = getColor(string); - if(!isValidColor(color)) { - console.warn('"' + string + '" is not a valid color.'); - } else { - validColors.push(color); - } - }); - return validColors; - } - - setMeasures() { - // Override measures, including those for title and legend - // set config for legend and title - } - - configure() { - let height = this.argHeight; - this.baseHeight = height; - this.height = height - getExtraHeight(this.measures); - - // Bind window events - this.boundDrawFn = () => this.draw(true); - if (ResizeObserver) { - this.resizeObserver = new ResizeObserver(this.boundDrawFn); - this.resizeObserver.observe(this.parent); - } - window.addEventListener('resize', this.boundDrawFn); - window.addEventListener('orientationchange', this.boundDrawFn); - } - - destroy() { - if (this.resizeObserver) this.resizeObserver.disconnect(); - window.removeEventListener('resize', this.boundDrawFn); - window.removeEventListener('orientationchange', this.boundDrawFn); - } - - // Has to be called manually - setup() { - this.makeContainer(); - this.updateWidth(); - this.makeTooltip(); - - this.draw(false, true); - } - - makeContainer() { - // Chart needs a dedicated parent element - this.parent.innerHTML = ''; - - let args = { - inside: this.parent, - className: 'chart-container' - }; - - if(this.independentWidth) { - args.styles = { width: this.independentWidth + 'px' }; - } - - this.container = $.create('div', args); - } - - makeTooltip() { - this.tip = new SvgTip({ - parent: this.container, - colors: this.colors - }); - this.bindTooltip(); - } - - bindTooltip() {} - - draw(onlyWidthChange=false, init=false) { - if (onlyWidthChange && isHidden(this.parent)) { - // Don't update anything if the chart is hidden - return; - } - this.updateWidth(); - - this.calc(onlyWidthChange); - this.makeChartArea(); - this.setupComponents(); - - this.components.forEach(c => c.setup(this.drawArea)); - // this.components.forEach(c => c.make()); - this.render(this.components, false); - - if(init) { - this.data = this.realData; - setTimeout(() => {this.update(this.data);}, this.initTimeout); - } - - this.renderLegend(); - - this.setupNavigation(init); - } - - calc() {} // builds state - - updateWidth() { - this.baseWidth = getElementContentWidth(this.parent); - this.width = this.baseWidth - getExtraWidth(this.measures); - } - - makeChartArea() { - if(this.svg) { - this.container.removeChild(this.svg); - } - let m = this.measures; - - this.svg = makeSVGContainer( - this.container, - 'frappe-chart chart', - this.baseWidth, - this.baseHeight - ); - this.svgDefs = makeSVGDefs(this.svg); - - if(this.title.length) { - this.titleEL = makeText( - 'title', - m.margins.left, - m.margins.top, - this.title, - { - fontSize: m.titleFontSize, - fill: '#666666', - dy: m.titleFontSize - } - ); - } - - let top = getTopOffset(m); - this.drawArea = makeSVGGroup( - this.type + '-chart chart-draw-area', - `translate(${getLeftOffset(m)}, ${top})` - ); - - if(this.config.showLegend) { - top += this.height + m.paddings.bottom; - this.legendArea = makeSVGGroup( - 'chart-legend', - `translate(${getLeftOffset(m)}, ${top})` - ); - } - - if(this.title.length) { this.svg.appendChild(this.titleEL); } - this.svg.appendChild(this.drawArea); - if(this.config.showLegend) { this.svg.appendChild(this.legendArea); } - - this.updateTipOffset(getLeftOffset(m), getTopOffset(m)); - } - - updateTipOffset(x, y) { - this.tip.offset = { - x: x, - y: y - }; - } - - setupComponents() { this.components = new Map(); } - - update(data) { - if(!data) { - console.error('No data to update.'); - } - this.data = this.prepareData(data); - this.calc(); // builds state - this.render(this.components, this.config.animate); - this.renderLegend(); - } - - render(components=this.components, animate=true) { - if(this.config.isNavigable) { - // Remove all existing overlays - this.overlays.map(o => o.parentNode.removeChild(o)); - // ref.parentNode.insertBefore(element, ref); - } - let elementsToAnimate = []; - // Can decouple to this.refreshComponents() first to save animation timeout - components.forEach(c => { - elementsToAnimate = elementsToAnimate.concat(c.update(animate)); - }); - if(elementsToAnimate.length > 0) { - runSMILAnimation(this.container, this.svg, elementsToAnimate); - setTimeout(() => { - components.forEach(c => c.make()); - this.updateNav(); - }, CHART_POST_ANIMATE_TIMEOUT); - } else { - components.forEach(c => c.make()); - this.updateNav(); - } - } - - updateNav() { - if(this.config.isNavigable) { - this.makeOverlay(); - this.bindUnits(); - } - } - - renderLegend() {} - - setupNavigation(init=false) { - if(!this.config.isNavigable) return; - - if(init) { - this.bindOverlay(); - - this.keyActions = { - '13': this.onEnterKey.bind(this), - '37': this.onLeftArrow.bind(this), - '38': this.onUpArrow.bind(this), - '39': this.onRightArrow.bind(this), - '40': this.onDownArrow.bind(this), - }; - - document.addEventListener('keydown', (e) => { - if(isElementInViewport(this.container)) { - e = e || window.event; - if(this.keyActions[e.keyCode]) { - this.keyActions[e.keyCode](); - } - } - }); - } - } - - makeOverlay() {} - updateOverlay() {} - bindOverlay() {} - bindUnits() {} - - onLeftArrow() {} - onRightArrow() {} - onUpArrow() {} - onDownArrow() {} - onEnterKey() {} - - addDataPoint() {} - removeDataPoint() {} - - getDataPoint() {} - setCurrentDataPoint() {} - - updateDataset() {} - - export() { - let chartSvg = prepareForExport(this.svg); - downloadFile(this.title || 'Chart', [chartSvg]); - } -} diff --git a/node_modules/frappe-charts/src/js/charts/DonutChart.js b/node_modules/frappe-charts/src/js/charts/DonutChart.js deleted file mode 100644 index b0ae67b..0000000 --- a/node_modules/frappe-charts/src/js/charts/DonutChart.js +++ /dev/null @@ -1,161 +0,0 @@ -import AggregationChart from './AggregationChart'; -import { getComponent } from '../objects/ChartComponents'; -import { getOffset } from '../utils/dom'; -import { getPositionByAngle } from '../utils/helpers'; -import { makeArcStrokePathStr, makeStrokeCircleStr } from '../utils/draw'; -import { lightenDarkenColor } from '../utils/colors'; -import { transform } from '../utils/animation'; -import { FULL_ANGLE } from '../utils/constants'; - -export default class DonutChart extends AggregationChart { - constructor(parent, args) { - super(parent, args); - this.type = 'donut'; - this.initTimeout = 0; - this.init = 1; - - this.setup(); - } - - configure(args) { - super.configure(args); - this.mouseMove = this.mouseMove.bind(this); - this.mouseLeave = this.mouseLeave.bind(this); - - this.hoverRadio = args.hoverRadio || 0.1; - this.config.startAngle = args.startAngle || 0; - - this.clockWise = args.clockWise || false; - this.strokeWidth = args.strokeWidth || 30; - } - - calc() { - super.calc(); - let s = this.state; - this.radius = - this.height > this.width - ? this.center.x - this.strokeWidth / 2 - : this.center.y - this.strokeWidth / 2; - - const { radius, clockWise } = this; - - const prevSlicesProperties = s.slicesProperties || []; - s.sliceStrings = []; - s.slicesProperties = []; - let curAngle = 180 - this.config.startAngle; - - s.sliceTotals.map((total, i) => { - const startAngle = curAngle; - const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE; - const largeArc = originDiffAngle > 180 ? 1: 0; - const diffAngle = clockWise ? -originDiffAngle : originDiffAngle; - const endAngle = curAngle = curAngle + diffAngle; - const startPosition = getPositionByAngle(startAngle, radius); - const endPosition = getPositionByAngle(endAngle, radius); - - const prevProperty = this.init && prevSlicesProperties[i]; - - let curStart,curEnd; - if(this.init) { - curStart = prevProperty ? prevProperty.startPosition : startPosition; - curEnd = prevProperty ? prevProperty.endPosition : startPosition; - } else { - curStart = startPosition; - curEnd = endPosition; - } - const curPath = - originDiffAngle === 360 - ? makeStrokeCircleStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc) - : makeArcStrokePathStr(curStart, curEnd, this.center, this.radius, this.clockWise, largeArc); - - s.sliceStrings.push(curPath); - s.slicesProperties.push({ - startPosition, - endPosition, - value: total, - total: s.grandTotal, - startAngle, - endAngle, - angle: diffAngle - }); - - }); - this.init = 0; - } - - setupComponents() { - let s = this.state; - - let componentConfigs = [ - [ - 'donutSlices', - { }, - function() { - return { - sliceStrings: s.sliceStrings, - colors: this.colors, - strokeWidth: this.strokeWidth, - }; - }.bind(this) - ] - ]; - - this.components = new Map(componentConfigs - .map(args => { - let component = getComponent(...args); - return [args[0], component]; - })); - } - - calTranslateByAngle(property){ - const{ radius, hoverRadio } = this; - const position = getPositionByAngle(property.startAngle+(property.angle / 2),radius); - return `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`; - } - - hoverSlice(path,i,flag,e){ - if(!path) return; - const color = this.colors[i]; - if(flag) { - transform(path, this.calTranslateByAngle(this.state.slicesProperties[i])); - path.style.stroke = lightenDarkenColor(color, 50); - let g_off = getOffset(this.svg); - let x = e.pageX - g_off.left + 10; - let y = e.pageY - g_off.top - 10; - let title = (this.formatted_labels && this.formatted_labels.length > 0 - ? this.formatted_labels[i] : this.state.labels[i]) + ': '; - let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1); - this.tip.setValues(x, y, {name: title, value: percent + "%"}); - this.tip.showTip(); - } else { - transform(path,'translate3d(0,0,0)'); - this.tip.hideTip(); - path.style.stroke = color; - } - } - - bindTooltip() { - this.container.addEventListener('mousemove', this.mouseMove); - this.container.addEventListener('mouseleave', this.mouseLeave); - } - - mouseMove(e){ - const target = e.target; - let slices = this.components.get('donutSlices').store; - let prevIndex = this.curActiveSliceIndex; - let prevAcitve = this.curActiveSlice; - if(slices.includes(target)) { - let i = slices.indexOf(target); - this.hoverSlice(prevAcitve, prevIndex,false); - this.curActiveSlice = target; - this.curActiveSliceIndex = i; - this.hoverSlice(target, i, true, e); - } else { - this.mouseLeave(); - } - } - - mouseLeave(){ - this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false); - } -} diff --git a/node_modules/frappe-charts/src/js/charts/Heatmap.js b/node_modules/frappe-charts/src/js/charts/Heatmap.js deleted file mode 100644 index dacb10e..0000000 --- a/node_modules/frappe-charts/src/js/charts/Heatmap.js +++ /dev/null @@ -1,296 +0,0 @@ -import BaseChart from './BaseChart'; -import { getComponent } from '../objects/ChartComponents'; -import { makeText, heatSquare } from '../utils/draw'; -import { DAY_NAMES_SHORT, addDays, areInSameMonth, getLastDateInMonth, setDayToSunday, getYyyyMmDd, getWeeksBetween, getMonthName, clone, - NO_OF_MILLIS, NO_OF_YEAR_MONTHS, NO_OF_DAYS_IN_WEEK } from '../utils/date-utils'; -import { calcDistribution, getMaxCheckpoint } from '../utils/intervals'; -import { getExtraHeight, getExtraWidth, HEATMAP_DISTRIBUTION_SIZE, HEATMAP_SQUARE_SIZE, - HEATMAP_GUTTER_SIZE } from '../utils/constants'; - -const COL_WIDTH = HEATMAP_SQUARE_SIZE + HEATMAP_GUTTER_SIZE; -const ROW_HEIGHT = COL_WIDTH; -// const DAY_INCR = 1; - -export default class Heatmap extends BaseChart { - constructor(parent, options) { - super(parent, options); - this.type = 'heatmap'; - - this.countLabel = options.countLabel || ''; - - let validStarts = ['Sunday', 'Monday']; - let startSubDomain = validStarts.includes(options.startSubDomain) - ? options.startSubDomain : 'Sunday'; - this.startSubDomainIndex = validStarts.indexOf(startSubDomain); - - this.setup(); - } - - setMeasures(options) { - let m = this.measures; - this.discreteDomains = options.discreteDomains === 0 ? 0 : 1; - - m.paddings.top = ROW_HEIGHT * 3; - m.paddings.bottom = 0; - m.legendHeight = ROW_HEIGHT * 2; - m.baseHeight = ROW_HEIGHT * NO_OF_DAYS_IN_WEEK - + getExtraHeight(m); - - let d = this.data; - let spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0; - this.independentWidth = (getWeeksBetween(d.start, d.end) - + spacing) * COL_WIDTH + getExtraWidth(m); - } - - updateWidth() { - let spacing = this.discreteDomains ? NO_OF_YEAR_MONTHS : 0; - let noOfWeeks = this.state.noOfWeeks ? this.state.noOfWeeks : 52; - this.baseWidth = (noOfWeeks + spacing) * COL_WIDTH - + getExtraWidth(this.measures); - } - - prepareData(data=this.data) { - if(data.start && data.end && data.start > data.end) { - throw new Error('Start date cannot be greater than end date.'); - } - - if(!data.start) { - data.start = new Date(); - data.start.setFullYear( data.start.getFullYear() - 1 ); - } - if(!data.end) { data.end = new Date(); } - data.dataPoints = data.dataPoints || {}; - - if(parseInt(Object.keys(data.dataPoints)[0]) > 100000) { - let points = {}; - Object.keys(data.dataPoints).forEach(timestampSec => { - let date = new Date(timestampSec * NO_OF_MILLIS); - points[getYyyyMmDd(date)] = data.dataPoints[timestampSec]; - }); - data.dataPoints = points; - } - - return data; - } - - calc() { - let s = this.state; - - s.start = clone(this.data.start); - s.end = clone(this.data.end); - - s.firstWeekStart = clone(s.start); - s.noOfWeeks = getWeeksBetween(s.start, s.end); - s.distribution = calcDistribution( - Object.values(this.data.dataPoints), HEATMAP_DISTRIBUTION_SIZE); - - s.domainConfigs = this.getDomains(); - } - - setupComponents() { - let s = this.state; - let lessCol = this.discreteDomains ? 0 : 1; - - let componentConfigs = s.domainConfigs.map((config, i) => [ - 'heatDomain', - { - index: config.index, - colWidth: COL_WIDTH, - rowHeight: ROW_HEIGHT, - squareSize: HEATMAP_SQUARE_SIZE, - radius: this.rawChartArgs.radius || 0, - xTranslate: s.domainConfigs - .filter((config, j) => j < i) - .map(config => config.cols.length - lessCol) - .reduce((a, b) => a + b, 0) - * COL_WIDTH - }, - function() { - return s.domainConfigs[i]; - }.bind(this) - - ]); - - this.components = new Map(componentConfigs - .map((args, i) => { - let component = getComponent(...args); - return [args[0] + '-' + i, component]; - }) - ); - - let y = 0; - DAY_NAMES_SHORT.forEach((dayName, i) => { - if([1, 3, 5].includes(i)) { - let dayText = makeText('subdomain-name', -COL_WIDTH/2, y, dayName, - { - fontSize: HEATMAP_SQUARE_SIZE, - dy: 8, - textAnchor: 'end' - } - ); - this.drawArea.appendChild(dayText); - } - y += ROW_HEIGHT; - }); - } - - update(data) { - if(!data) { - console.error('No data to update.'); - } - - this.data = this.prepareData(data); - this.draw(); - this.bindTooltip(); - } - - bindTooltip() { - this.container.addEventListener('mousemove', (e) => { - this.components.forEach(comp => { - let daySquares = comp.store; - let daySquare = e.target; - if(daySquares.includes(daySquare)) { - - let count = daySquare.getAttribute('data-value'); - let dateParts = daySquare.getAttribute('data-date').split('-'); - - let month = getMonthName(parseInt(dateParts[1])-1, true); - - let gOff = this.container.getBoundingClientRect(), pOff = daySquare.getBoundingClientRect(); - - let width = parseInt(e.target.getAttribute('width')); - let x = pOff.left - gOff.left + width/2; - let y = pOff.top - gOff.top; - let value = count + ' ' + this.countLabel; - let name = ' on ' + month + ' ' + dateParts[0] + ', ' + dateParts[2]; - - this.tip.setValues(x, y, {name: name, value: value, valueFirst: 1}, []); - this.tip.showTip(); - } - }); - }); - } - - renderLegend() { - this.legendArea.textContent = ''; - let x = 0; - let y = ROW_HEIGHT; - let radius = this.rawChartArgs.radius || 0; - - let lessText = makeText('subdomain-name', x, y, 'Less', - { - fontSize: HEATMAP_SQUARE_SIZE + 1, - dy: 9 - } - ); - x = (COL_WIDTH * 2) + COL_WIDTH/2; - this.legendArea.appendChild(lessText); - - this.colors.slice(0, HEATMAP_DISTRIBUTION_SIZE).map((color, i) => { - const square = heatSquare('heatmap-legend-unit', x + (COL_WIDTH + 3) * i, - y, HEATMAP_SQUARE_SIZE, radius, color); - this.legendArea.appendChild(square); - }); - - let moreTextX = x + HEATMAP_DISTRIBUTION_SIZE * (COL_WIDTH + 3) + COL_WIDTH/4; - let moreText = makeText('subdomain-name', moreTextX, y, 'More', - { - fontSize: HEATMAP_SQUARE_SIZE + 1, - dy: 9 - } - ); - this.legendArea.appendChild(moreText); - } - - getDomains() { - let s = this.state; - const [startMonth, startYear] = [s.start.getMonth(), s.start.getFullYear()]; - const [endMonth, endYear] = [s.end.getMonth(), s.end.getFullYear()]; - - const noOfMonths = (endMonth - startMonth + 1) + (endYear - startYear) * 12; - - let domainConfigs = []; - - let startOfMonth = clone(s.start); - for(var i = 0; i < noOfMonths; i++) { - let endDate = s.end; - if(!areInSameMonth(startOfMonth, s.end)) { - let [month, year] = [startOfMonth.getMonth(), startOfMonth.getFullYear()]; - endDate = getLastDateInMonth(month, year); - } - domainConfigs.push(this.getDomainConfig(startOfMonth, endDate)); - - addDays(endDate, 1); - startOfMonth = endDate; - } - - return domainConfigs; - } - - getDomainConfig(startDate, endDate='') { - let [month, year] = [startDate.getMonth(), startDate.getFullYear()]; - let startOfWeek = setDayToSunday(startDate); // TODO: Monday as well - endDate = clone(endDate) || getLastDateInMonth(month, year); - - let domainConfig = { - index: month, - cols: [] - }; - - addDays(endDate, 1); - let noOfMonthWeeks = getWeeksBetween(startOfWeek, endDate); - - let cols = [], col; - for(var i = 0; i < noOfMonthWeeks; i++) { - col = this.getCol(startOfWeek, month); - cols.push(col); - - startOfWeek = new Date(col[NO_OF_DAYS_IN_WEEK - 1].yyyyMmDd); - addDays(startOfWeek, 1); - } - - if(col[NO_OF_DAYS_IN_WEEK - 1].dataValue !== undefined) { - addDays(startOfWeek, 1); - cols.push(this.getCol(startOfWeek, month, true)); - } - - domainConfig.cols = cols; - - return domainConfig; - } - - getCol(startDate, month, empty = false) { - let s = this.state; - - // startDate is the start of week - let currentDate = clone(startDate); - let col = []; - - for(var i = 0; i < NO_OF_DAYS_IN_WEEK; i++, addDays(currentDate, 1)) { - let config = {}; - - // Non-generic adjustment for entire heatmap, needs state - let currentDateWithinData = currentDate >= s.start && currentDate <= s.end; - - if(empty || currentDate.getMonth() !== month || !currentDateWithinData) { - config.yyyyMmDd = getYyyyMmDd(currentDate); - } else { - config = this.getSubDomainConfig(currentDate); - } - col.push(config); - } - - return col; - } - - getSubDomainConfig(date) { - let yyyyMmDd = getYyyyMmDd(date); - let dataValue = this.data.dataPoints[yyyyMmDd]; - let config = { - yyyyMmDd: yyyyMmDd, - dataValue: dataValue || 0, - fill: this.colors[getMaxCheckpoint(dataValue, this.state.distribution)] - }; - return config; - } -} diff --git a/node_modules/frappe-charts/src/js/charts/MultiAxisChart.js b/node_modules/frappe-charts/src/js/charts/MultiAxisChart.js deleted file mode 100644 index 69cfb4f..0000000 --- a/node_modules/frappe-charts/src/js/charts/MultiAxisChart.js +++ /dev/null @@ -1,173 +0,0 @@ -import AxisChart from './AxisChart'; -import { Y_AXIS_MARGIN } from '../utils/constants'; -// import { ChartComponent } from '../objects/ChartComponents'; -import { floatTwo } from '../utils/helpers'; - -export default class MultiAxisChart extends AxisChart { - constructor(args) { - super(args); - // this.unitType = args.unitType || 'line'; - // this.setup(); - } - - preSetup() { - this.type = 'multiaxis'; - } - - setMeasures() { - super.setMeasures(); - let noOfLeftAxes = this.data.datasets.filter(d => d.axisPosition === 'left').length; - this.measures.margins.left = (noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN; - this.measures.margins.right = (this.data.datasets.length - noOfLeftAxes) * Y_AXIS_MARGIN || Y_AXIS_MARGIN; - } - - prepareYAxis() { } - - prepareData(data) { - super.prepareData(data); - let sets = this.state.datasets; - // let axesLeft = sets.filter(d => d.axisPosition === 'left'); - // let axesRight = sets.filter(d => d.axisPosition === 'right'); - // let axesNone = sets.filter(d => !d.axisPosition || - // !['left', 'right'].includes(d.axisPosition)); - - let leftCount = 0, rightCount = 0; - - sets.forEach((d, i) => { - d.yAxis = { - position: d.axisPosition, - index: d.axisPosition === 'left' ? leftCount++ : rightCount++ - }; - }); - } - - configure(args) { - super.configure(args); - this.config.xAxisMode = args.xAxisMode || 'tick'; - this.config.yAxisMode = args.yAxisMode || 'span'; - } - - // setUnitWidthAndXOffset() { - // this.state.unitWidth = this.width/(this.state.datasetLength); - // this.state.xOffset = this.state.unitWidth/2; - // } - - configUnits() { - this.unitArgs = { - type: 'bar', - args: { - spaceWidth: this.state.unitWidth/2, - } - }; - } - - setYAxis() { - this.state.datasets.map(d => { - this.calcYAxisParameters(d.yAxis, d.values, this.unitType === 'line'); - }); - } - - calcYUnits() { - this.state.datasets.map(d => { - d.positions = d.values.map(val => floatTwo(d.yAxis.zeroLine - val * d.yAxis.scaleMultiplier)); - }); - } - - // TODO: function doesn't exist, handle with components - renderConstants() { - this.state.datasets.map(d => { - let guidePos = d.yAxis.position === 'left' - ? -1 * d.yAxis.index * Y_AXIS_MARGIN - : this.width + d.yAxis.index * Y_AXIS_MARGIN; - this.renderer.xLine(guidePos, '', { - pos:'top', - mode: 'span', - stroke: this.colors[i], - className: 'y-axis-guide' - }) - }); - } - - getYAxesComponents() { - return this.data.datasets.map((e, i) => { - return new ChartComponent({ - layerClass: 'y axis y-axis-' + i, - make: () => { - let yAxis = this.state.datasets[i].yAxis; - this.renderer.setZeroline(yAxis.zeroline); - let options = { - pos: yAxis.position, - mode: 'tick', - offset: yAxis.index * Y_AXIS_MARGIN, - stroke: this.colors[i] - }; - - return yAxis.positions.map((position, j) => - this.renderer.yLine(position, yAxis.labels[j], options) - ); - }, - animate: () => {} - }); - }); - } - - // TODO remove renderer zeroline from above and below - getChartComponents() { - return this.data.datasets.map((d, index) => { - return new ChartComponent({ - layerClass: 'dataset-units dataset-' + index, - make: () => { - let d = this.state.datasets[index]; - let unitType = this.unitArgs; - - // the only difference, should be tied to datasets or default - this.renderer.setZeroline(d.yAxis.zeroLine); - - return d.positions.map((y, j) => { - return this.renderer[unitType.type]( - this.state.xAxisPositions[j], - y, - unitType.args, - this.colors[index], - j, - index, - this.state.datasetLength - ); - }); - }, - animate: (svgUnits) => { - let d = this.state.datasets[index]; - let unitType = this.unitArgs.type; - - // have been updated in axis render; - let newX = this.state.xAxisPositions; - let newY = this.state.datasets[index].positions; - - let lastUnit = svgUnits[svgUnits.length - 1]; - let parentNode = lastUnit.parentNode; - - if(this.oldState.xExtra > 0) { - for(var i = 0; i { - if(newX[i] === undefined || newY[i] === undefined) return; - this.elementsToAnimate.push(this.renderer['animate' + unitType]( - unit, // unit, with info to replace where it came from in the data - newX[i], - newY[i], - index, - this.state.noOfDatasets - )); - }); - } - }); - }); - } -} diff --git a/node_modules/frappe-charts/src/js/charts/PercentageChart.js b/node_modules/frappe-charts/src/js/charts/PercentageChart.js deleted file mode 100644 index cd91469..0000000 --- a/node_modules/frappe-charts/src/js/charts/PercentageChart.js +++ /dev/null @@ -1,92 +0,0 @@ -import AggregationChart from './AggregationChart'; -import { getOffset } from '../utils/dom'; -import { getComponent } from '../objects/ChartComponents'; -import { PERCENTAGE_BAR_DEFAULT_HEIGHT, PERCENTAGE_BAR_DEFAULT_DEPTH } from '../utils/constants'; - -export default class PercentageChart extends AggregationChart { - constructor(parent, args) { - super(parent, args); - this.type = 'percentage'; - this.setup(); - } - - setMeasures(options) { - let m = this.measures; - this.barOptions = options.barOptions || {}; - - let b = this.barOptions; - b.height = b.height || PERCENTAGE_BAR_DEFAULT_HEIGHT; - b.depth = b.depth || PERCENTAGE_BAR_DEFAULT_DEPTH; - - m.paddings.right = 30; - m.legendHeight = 60; - m.baseHeight = (b.height + b.depth * 0.5) * 8; - } - - setupComponents() { - let s = this.state; - - let componentConfigs = [ - [ - 'percentageBars', - { - barHeight: this.barOptions.height, - barDepth: this.barOptions.depth, - }, - function() { - return { - xPositions: s.xPositions, - widths: s.widths, - colors: this.colors - }; - }.bind(this) - ] - ]; - - this.components = new Map(componentConfigs - .map(args => { - let component = getComponent(...args); - return [args[0], component]; - })); - } - - calc() { - super.calc(); - let s = this.state; - - s.xPositions = []; - s.widths = []; - - let xPos = 0; - s.sliceTotals.map((value) => { - let width = this.width * value / s.grandTotal; - s.widths.push(width); - s.xPositions.push(xPos); - xPos += width; - }); - } - - makeDataByIndex() { } - - bindTooltip() { - let s = this.state; - this.container.addEventListener('mousemove', (e) => { - let bars = this.components.get('percentageBars').store; - let bar = e.target; - if(bars.includes(bar)) { - - let i = bars.indexOf(bar); - let gOff = getOffset(this.container), pOff = getOffset(bar); - - let x = pOff.left - gOff.left + parseInt(bar.getAttribute('width'))/2; - let y = pOff.top - gOff.top; - let title = (this.formattedLabels && this.formattedLabels.length>0 - ? this.formattedLabels[i] : this.state.labels[i]) + ': '; - let fraction = s.sliceTotals[i]/s.grandTotal; - - this.tip.setValues(x, y, {name: title, value: (fraction*100).toFixed(1) + "%"}); - this.tip.showTip(); - } - }); - } -} diff --git a/node_modules/frappe-charts/src/js/charts/PieChart.js b/node_modules/frappe-charts/src/js/charts/PieChart.js deleted file mode 100644 index 656f108..0000000 --- a/node_modules/frappe-charts/src/js/charts/PieChart.js +++ /dev/null @@ -1,155 +0,0 @@ -import AggregationChart from './AggregationChart'; -import { getComponent } from '../objects/ChartComponents'; -import { getOffset } from '../utils/dom'; -import { getPositionByAngle } from '../utils/helpers'; -import { makeArcPathStr, makeCircleStr } from '../utils/draw'; -import { lightenDarkenColor } from '../utils/colors'; -import { transform } from '../utils/animation'; -import { FULL_ANGLE } from '../utils/constants'; - -export default class PieChart extends AggregationChart { - constructor(parent, args) { - super(parent, args); - this.type = 'pie'; - this.initTimeout = 0; - this.init = 1; - - this.setup(); - } - - configure(args) { - super.configure(args); - this.mouseMove = this.mouseMove.bind(this); - this.mouseLeave = this.mouseLeave.bind(this); - - this.hoverRadio = args.hoverRadio || 0.1; - this.config.startAngle = args.startAngle || 0; - - this.clockWise = args.clockWise || false; - } - - calc() { - super.calc(); - let s = this.state; - this.radius = (this.height > this.width ? this.center.x : this.center.y); - - const { radius, clockWise } = this; - - const prevSlicesProperties = s.slicesProperties || []; - s.sliceStrings = []; - s.slicesProperties = []; - let curAngle = 180 - this.config.startAngle; - s.sliceTotals.map((total, i) => { - const startAngle = curAngle; - const originDiffAngle = (total / s.grandTotal) * FULL_ANGLE; - const largeArc = originDiffAngle > 180 ? 1: 0; - const diffAngle = clockWise ? -originDiffAngle : originDiffAngle; - const endAngle = curAngle = curAngle + diffAngle; - const startPosition = getPositionByAngle(startAngle, radius); - const endPosition = getPositionByAngle(endAngle, radius); - - const prevProperty = this.init && prevSlicesProperties[i]; - - let curStart,curEnd; - if(this.init) { - curStart = prevProperty ? prevProperty.startPosition : startPosition; - curEnd = prevProperty ? prevProperty.endPosition : startPosition; - } else { - curStart = startPosition; - curEnd = endPosition; - } - const curPath = - originDiffAngle === 360 - ? makeCircleStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc) - : makeArcPathStr(curStart, curEnd, this.center, this.radius, clockWise, largeArc); - - s.sliceStrings.push(curPath); - s.slicesProperties.push({ - startPosition, - endPosition, - value: total, - total: s.grandTotal, - startAngle, - endAngle, - angle: diffAngle - }); - - }); - this.init = 0; - } - - setupComponents() { - let s = this.state; - - let componentConfigs = [ - [ - 'pieSlices', - { }, - function() { - return { - sliceStrings: s.sliceStrings, - colors: this.colors - }; - }.bind(this) - ] - ]; - - this.components = new Map(componentConfigs - .map(args => { - let component = getComponent(...args); - return [args[0], component]; - })); - } - - calTranslateByAngle(property){ - const{radius,hoverRadio} = this; - const position = getPositionByAngle(property.startAngle+(property.angle / 2),radius); - return `translate3d(${(position.x) * hoverRadio}px,${(position.y) * hoverRadio}px,0)`; - } - - hoverSlice(path,i,flag,e){ - if(!path) return; - const color = this.colors[i]; - if(flag) { - transform(path, this.calTranslateByAngle(this.state.slicesProperties[i])); - path.style.fill = lightenDarkenColor(color, 50); - let g_off = getOffset(this.svg); - let x = e.pageX - g_off.left + 10; - let y = e.pageY - g_off.top - 10; - let title = (this.formatted_labels && this.formatted_labels.length > 0 - ? this.formatted_labels[i] : this.state.labels[i]) + ': '; - let percent = (this.state.sliceTotals[i] * 100 / this.state.grandTotal).toFixed(1); - this.tip.setValues(x, y, {name: title, value: percent + "%"}); - this.tip.showTip(); - } else { - transform(path,'translate3d(0,0,0)'); - this.tip.hideTip(); - path.style.fill = color; - } - } - - bindTooltip() { - this.container.addEventListener('mousemove', this.mouseMove); - this.container.addEventListener('mouseleave', this.mouseLeave); - } - - mouseMove(e){ - const target = e.target; - let slices = this.components.get('pieSlices').store; - let prevIndex = this.curActiveSliceIndex; - let prevAcitve = this.curActiveSlice; - if(slices.includes(target)) { - let i = slices.indexOf(target); - this.hoverSlice(prevAcitve, prevIndex,false); - this.curActiveSlice = target; - this.curActiveSliceIndex = i; - this.hoverSlice(target, i, true, e); - } else { - this.mouseLeave(); - } - } - - mouseLeave(){ - this.hoverSlice(this.curActiveSlice,this.curActiveSliceIndex,false); - } -} diff --git a/node_modules/frappe-charts/src/js/index.js b/node_modules/frappe-charts/src/js/index.js deleted file mode 100644 index 5ce3c59..0000000 --- a/node_modules/frappe-charts/src/js/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import * as Charts from './chart'; - -let frappe = { }; - -frappe.NAME = 'Frappe Charts'; -frappe.VERSION = '1.6.2'; - -frappe = Object.assign({ }, frappe, Charts); - -export default frappe; \ No newline at end of file diff --git a/node_modules/frappe-charts/src/js/objects/ChartComponents.js b/node_modules/frappe-charts/src/js/objects/ChartComponents.js deleted file mode 100644 index ea1a096..0000000 --- a/node_modules/frappe-charts/src/js/objects/ChartComponents.js +++ /dev/null @@ -1,446 +0,0 @@ -import { makeSVGGroup } from '../utils/draw'; -import { makeText, makePath, xLine, yLine, yMarker, yRegion, datasetBar, datasetDot, percentageBar, getPaths, heatSquare } from '../utils/draw'; -import { equilizeNoOfElements } from '../utils/draw-utils'; -import { translateHoriLine, translateVertLine, animateRegion, animateBar, - animateDot, animatePath, animatePathStr } from '../utils/animate'; -import { getMonthName } from '../utils/date-utils'; - -class ChartComponent { - constructor({ - layerClass = '', - layerTransform = '', - constants, - - getData, - makeElements, - animateElements - }) { - this.layerTransform = layerTransform; - this.constants = constants; - - this.makeElements = makeElements; - this.getData = getData; - - this.animateElements = animateElements; - - this.store = []; - this.labels = []; - - this.layerClass = layerClass; - this.layerClass = typeof(this.layerClass) === 'function' - ? this.layerClass() : this.layerClass; - - this.refresh(); - } - - refresh(data) { - this.data = data || this.getData(); - } - - setup(parent) { - this.layer = makeSVGGroup(this.layerClass, this.layerTransform, parent); - } - - make() { - this.render(this.data); - this.oldData = this.data; - } - - render(data) { - this.store = this.makeElements(data); - - this.layer.textContent = ''; - this.store.forEach(element => { - this.layer.appendChild(element); - }); - this.labels.forEach(element => { - this.layer.appendChild(element); - }); - } - - update(animate = true) { - this.refresh(); - let animateElements = []; - if(animate) { - animateElements = this.animateElements(this.data) || []; - } - return animateElements; - } -} - -let componentConfigs = { - donutSlices: { - layerClass: 'donut-slices', - makeElements(data) { - return data.sliceStrings.map((s, i) => { - let slice = makePath(s, 'donut-path', data.colors[i], 'none', data.strokeWidth); - slice.style.transition = 'transform .3s;'; - return slice; - }); - }, - - animateElements(newData) { - return this.store.map((slice, i) => animatePathStr(slice, newData.sliceStrings[i])); - }, - }, - pieSlices: { - layerClass: 'pie-slices', - makeElements(data) { - return data.sliceStrings.map((s, i) =>{ - let slice = makePath(s, 'pie-path', 'none', data.colors[i]); - slice.style.transition = 'transform .3s;'; - return slice; - }); - }, - - animateElements(newData) { - return this.store.map((slice, i) => - animatePathStr(slice, newData.sliceStrings[i]) - ); - } - }, - percentageBars: { - layerClass: 'percentage-bars', - makeElements(data) { - return data.xPositions.map((x, i) =>{ - let y = 0; - let bar = percentageBar(x, y, data.widths[i], - this.constants.barHeight, this.constants.barDepth, data.colors[i]); - return bar; - }); - }, - - animateElements(newData) { - if(newData) return []; - } - }, - yAxis: { - layerClass: 'y axis', - makeElements(data) { - return data.positions.map((position, i) => - yLine(position, data.labels[i], this.constants.width, - {mode: this.constants.mode, pos: this.constants.pos, shortenNumbers: this.constants.shortenNumbers}) - ); - }, - - animateElements(newData) { - let newPos = newData.positions; - let newLabels = newData.labels; - let oldPos = this.oldData.positions; - let oldLabels = this.oldData.labels; - - [oldPos, newPos] = equilizeNoOfElements(oldPos, newPos); - [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels); - - this.render({ - positions: oldPos, - labels: newLabels - }); - - return this.store.map((line, i) => { - return translateHoriLine( - line, newPos[i], oldPos[i] - ); - }); - } - }, - - xAxis: { - layerClass: 'x axis', - makeElements(data) { - return data.positions.map((position, i) => - xLine(position, data.calcLabels[i], this.constants.height, - {mode: this.constants.mode, pos: this.constants.pos}) - ); - }, - - animateElements(newData) { - let newPos = newData.positions; - let newLabels = newData.calcLabels; - let oldPos = this.oldData.positions; - let oldLabels = this.oldData.calcLabels; - - [oldPos, newPos] = equilizeNoOfElements(oldPos, newPos); - [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels); - - this.render({ - positions: oldPos, - calcLabels: newLabels - }); - - return this.store.map((line, i) => { - return translateVertLine( - line, newPos[i], oldPos[i] - ); - }); - } - }, - - yMarkers: { - layerClass: 'y-markers', - makeElements(data) { - return data.map(m => - yMarker(m.position, m.label, this.constants.width, - {labelPos: m.options.labelPos, mode: 'span', lineType: 'dashed'}) - ); - }, - animateElements(newData) { - [this.oldData, newData] = equilizeNoOfElements(this.oldData, newData); - - let newPos = newData.map(d => d.position); - let newLabels = newData.map(d => d.label); - let newOptions = newData.map(d => d.options); - - let oldPos = this.oldData.map(d => d.position); - - this.render(oldPos.map((pos, i) => { - return { - position: oldPos[i], - label: newLabels[i], - options: newOptions[i] - }; - })); - - return this.store.map((line, i) => { - return translateHoriLine( - line, newPos[i], oldPos[i] - ); - }); - } - }, - - yRegions: { - layerClass: 'y-regions', - makeElements(data) { - return data.map(r => - yRegion(r.startPos, r.endPos, this.constants.width, - r.label, {labelPos: r.options.labelPos}) - ); - }, - animateElements(newData) { - [this.oldData, newData] = equilizeNoOfElements(this.oldData, newData); - - let newPos = newData.map(d => d.endPos); - let newLabels = newData.map(d => d.label); - let newStarts = newData.map(d => d.startPos); - let newOptions = newData.map(d => d.options); - - let oldPos = this.oldData.map(d => d.endPos); - let oldStarts = this.oldData.map(d => d.startPos); - - this.render(oldPos.map((pos, i) => { - return { - startPos: oldStarts[i], - endPos: oldPos[i], - label: newLabels[i], - options: newOptions[i] - }; - })); - - let animateElements = []; - - this.store.map((rectGroup, i) => { - animateElements = animateElements.concat(animateRegion( - rectGroup, newStarts[i], newPos[i], oldPos[i] - )); - }); - - return animateElements; - } - }, - - heatDomain: { - layerClass: function() { return 'heat-domain domain-' + this.constants.index; }, - makeElements(data) { - let {index, colWidth, rowHeight, squareSize, radius, xTranslate} = this.constants; - let monthNameHeight = -12; - let x = xTranslate, y = 0; - - this.serializedSubDomains = []; - - data.cols.map((week, weekNo) => { - if(weekNo === 1) { - this.labels.push( - makeText('domain-name', x, monthNameHeight, getMonthName(index, true).toUpperCase(), - { - fontSize: 9 - } - ) - ); - } - week.map((day, i) => { - if(day.fill) { - let data = { - 'data-date': day.yyyyMmDd, - 'data-value': day.dataValue, - 'data-day': i - }; - let square = heatSquare('day', x, y, squareSize, radius, day.fill, data); - this.serializedSubDomains.push(square); - } - y += rowHeight; - }); - y = 0; - x += colWidth; - }); - - return this.serializedSubDomains; - }, - - animateElements(newData) { - if(newData) return []; - } - }, - - barGraph: { - layerClass: function() { return 'dataset-units dataset-bars dataset-' + this.constants.index; }, - makeElements(data) { - let c = this.constants; - this.unitType = 'bar'; - this.units = data.yPositions.map((y, j) => { - return datasetBar( - data.xPositions[j], - y, - data.barWidth, - c.color, - data.labels[j], - j, - data.offsets[j], - { - zeroLine: data.zeroLine, - barsWidth: data.barsWidth, - minHeight: c.minHeight - } - ); - }); - return this.units; - }, - animateElements(newData) { - let newXPos = newData.xPositions; - let newYPos = newData.yPositions; - let newOffsets = newData.offsets; - let newLabels = newData.labels; - - let oldXPos = this.oldData.xPositions; - let oldYPos = this.oldData.yPositions; - let oldOffsets = this.oldData.offsets; - let oldLabels = this.oldData.labels; - - [oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos); - [oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos); - [oldOffsets, newOffsets] = equilizeNoOfElements(oldOffsets, newOffsets); - [oldLabels, newLabels] = equilizeNoOfElements(oldLabels, newLabels); - - this.render({ - xPositions: oldXPos, - yPositions: oldYPos, - offsets: oldOffsets, - labels: newLabels, - - zeroLine: this.oldData.zeroLine, - barsWidth: this.oldData.barsWidth, - barWidth: this.oldData.barWidth, - }); - - let animateElements = []; - - this.store.map((bar, i) => { - animateElements = animateElements.concat(animateBar( - bar, newXPos[i], newYPos[i], newData.barWidth, newOffsets[i], - {zeroLine: newData.zeroLine} - )); - }); - - return animateElements; - } - }, - - lineGraph: { - layerClass: function() { return 'dataset-units dataset-line dataset-' + this.constants.index; }, - makeElements(data) { - let c = this.constants; - this.unitType = 'dot'; - this.paths = {}; - if(!c.hideLine) { - this.paths = getPaths( - data.xPositions, - data.yPositions, - c.color, - { - heatline: c.heatline, - regionFill: c.regionFill, - spline: c.spline - }, - { - svgDefs: c.svgDefs, - zeroLine: data.zeroLine - } - ); - } - - this.units = []; - if(!c.hideDots) { - this.units = data.yPositions.map((y, j) => { - return datasetDot( - data.xPositions[j], - y, - data.radius, - c.color, - (c.valuesOverPoints ? data.values[j] : ''), - j - ); - }); - } - - return Object.values(this.paths).concat(this.units); - }, - animateElements(newData) { - let newXPos = newData.xPositions; - let newYPos = newData.yPositions; - let newValues = newData.values; - - let oldXPos = this.oldData.xPositions; - let oldYPos = this.oldData.yPositions; - let oldValues = this.oldData.values; - - [oldXPos, newXPos] = equilizeNoOfElements(oldXPos, newXPos); - [oldYPos, newYPos] = equilizeNoOfElements(oldYPos, newYPos); - [oldValues, newValues] = equilizeNoOfElements(oldValues, newValues); - - this.render({ - xPositions: oldXPos, - yPositions: oldYPos, - values: newValues, - - zeroLine: this.oldData.zeroLine, - radius: this.oldData.radius, - }); - - let animateElements = []; - - if(Object.keys(this.paths).length) { - animateElements = animateElements.concat(animatePath( - this.paths, newXPos, newYPos, newData.zeroLine, this.constants.spline)); - } - - if(this.units.length) { - this.units.map((dot, i) => { - animateElements = animateElements.concat(animateDot( - dot, newXPos[i], newYPos[i])); - }); - } - - return animateElements; - } - } -}; - -export function getComponent(name, constants, getData) { - let keys = Object.keys(componentConfigs).filter(k => name.includes(k)); - let config = componentConfigs[keys[0]]; - Object.assign(config, { - constants: constants, - getData: getData - }); - return new ChartComponent(config); -} diff --git a/node_modules/frappe-charts/src/js/objects/SvgTip.js b/node_modules/frappe-charts/src/js/objects/SvgTip.js deleted file mode 100644 index 2be1180..0000000 --- a/node_modules/frappe-charts/src/js/objects/SvgTip.js +++ /dev/null @@ -1,127 +0,0 @@ -import { $ } from '../utils/dom'; -import { TOOLTIP_POINTER_TRIANGLE_HEIGHT } from '../utils/constants'; - -export default class SvgTip { - constructor({ - parent = null, - colors = [] - }) { - this.parent = parent; - this.colors = colors; - this.titleName = ''; - this.titleValue = ''; - this.listValues = []; - this.titleValueFirst = 0; - - this.x = 0; - this.y = 0; - - this.top = 0; - this.left = 0; - - this.setup(); - } - - setup() { - this.makeTooltip(); - } - - refresh() { - this.fill(); - this.calcPosition(); - } - - makeTooltip() { - this.container = $.create('div', { - inside: this.parent, - className: 'graph-svg-tip comparison', - innerHTML: ` -
                  -
                  ` - }); - this.hideTip(); - - this.title = this.container.querySelector('.title'); - this.dataPointList = this.container.querySelector('.data-point-list'); - - this.parent.addEventListener('mouseleave', () => { - this.hideTip(); - }); - } - - fill() { - let title; - if(this.index) { - this.container.setAttribute('data-point-index', this.index); - } - if(this.titleValueFirst) { - title = `${this.titleValue}${this.titleName}`; - } else { - title = `${this.titleName}${this.titleValue}`; - } - this.title.innerHTML = title; - this.dataPointList.innerHTML = ''; - - this.listValues.map((set, i) => { - const color = this.colors[i] || 'black'; - let value = set.formatted === 0 || set.formatted ? set.formatted : set.value; - - let li = $.create('li', { - styles: { - 'border-top': `3px solid ${color}` - }, - innerHTML: `${ value === 0 || value ? value : '' } - ${set.title ? set.title : '' }` - }); - - this.dataPointList.appendChild(li); - }); - } - - calcPosition() { - let width = this.container.offsetWidth; - - this.top = this.y - this.container.offsetHeight - - TOOLTIP_POINTER_TRIANGLE_HEIGHT; - this.left = this.x - width/2; - let maxLeft = this.parent.offsetWidth - width; - - let pointer = this.container.querySelector('.svg-pointer'); - - if(this.left < 0) { - pointer.style.left = `calc(50% - ${-1 * this.left}px)`; - this.left = 0; - } else if(this.left > maxLeft) { - let delta = this.left - maxLeft; - let pointerOffset = `calc(50% + ${delta}px)`; - pointer.style.left = pointerOffset; - - this.left = maxLeft; - } else { - pointer.style.left = `50%`; - } - } - - setValues(x, y, title = {}, listValues = [], index = -1) { - this.titleName = title.name; - this.titleValue = title.value; - this.listValues = listValues; - this.x = x; - this.y = y; - this.titleValueFirst = title.valueFirst || 0; - this.index = index; - this.refresh(); - } - - hideTip() { - this.container.style.top = '0px'; - this.container.style.left = '0px'; - this.container.style.opacity = '0'; - } - - showTip() { - this.container.style.top = this.top + 'px'; - this.container.style.left = this.left + 'px'; - this.container.style.opacity = '1'; - } -} diff --git a/node_modules/frappe-charts/src/js/utils/animate.js b/node_modules/frappe-charts/src/js/utils/animate.js deleted file mode 100644 index 2cc6c8e..0000000 --- a/node_modules/frappe-charts/src/js/utils/animate.js +++ /dev/null @@ -1,105 +0,0 @@ -import { getBarHeightAndYAttr, getSplineCurvePointsStr } from './draw-utils'; - -export const UNIT_ANIM_DUR = 350; -export const PATH_ANIM_DUR = 350; -export const MARKER_LINE_ANIM_DUR = UNIT_ANIM_DUR; -export const REPLACE_ALL_NEW_DUR = 250; - -export const STD_EASING = 'easein'; - -export function translate(unit, oldCoord, newCoord, duration) { - let old = typeof oldCoord === 'string' ? oldCoord : oldCoord.join(', '); - return [ - unit, - {transform: newCoord.join(', ')}, - duration, - STD_EASING, - "translate", - {transform: old} - ]; -} - -export function translateVertLine(xLine, newX, oldX) { - return translate(xLine, [oldX, 0], [newX, 0], MARKER_LINE_ANIM_DUR); -} - -export function translateHoriLine(yLine, newY, oldY) { - return translate(yLine, [0, oldY], [0, newY], MARKER_LINE_ANIM_DUR); -} - -export function animateRegion(rectGroup, newY1, newY2, oldY2) { - let newHeight = newY1 - newY2; - let rect = rectGroup.childNodes[0]; - let width = rect.getAttribute("width"); - let rectAnim = [ - rect, - { height: newHeight, 'stroke-dasharray': `${width}, ${newHeight}` }, - MARKER_LINE_ANIM_DUR, - STD_EASING - ]; - - let groupAnim = translate(rectGroup, [0, oldY2], [0, newY2], MARKER_LINE_ANIM_DUR); - return [rectAnim, groupAnim]; -} - -export function animateBar(bar, x, yTop, width, offset=0, meta={}) { - let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine); - y -= offset; - if(bar.nodeName !== 'rect') { - let rect = bar.childNodes[0]; - let rectAnim = [ - rect, - {width: width, height: height}, - UNIT_ANIM_DUR, - STD_EASING - ]; - - let oldCoordStr = bar.getAttribute("transform").split("(")[1].slice(0, -1); - let groupAnim = translate(bar, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR); - return [rectAnim, groupAnim]; - } else { - return [[bar, {width: width, height: height, x: x, y: y}, UNIT_ANIM_DUR, STD_EASING]]; - } - // bar.animate({height: args.newHeight, y: yTop}, UNIT_ANIM_DUR, mina.easein); -} - -export function animateDot(dot, x, y) { - if(dot.nodeName !== 'circle') { - let oldCoordStr = dot.getAttribute("transform").split("(")[1].slice(0, -1); - let groupAnim = translate(dot, oldCoordStr, [x, y], MARKER_LINE_ANIM_DUR); - return [groupAnim]; - } else { - return [[dot, {cx: x, cy: y}, UNIT_ANIM_DUR, STD_EASING]]; - } - // dot.animate({cy: yTop}, UNIT_ANIM_DUR, mina.easein); -} - -export function animatePath(paths, newXList, newYList, zeroLine, spline) { - let pathComponents = []; - let pointsStr = newYList.map((y, i) => (newXList[i] + ',' + y)).join("L"); - - if (spline) - pointsStr = getSplineCurvePointsStr(newXList, newYList); - - const animPath = [paths.path, {d:"M" + pointsStr}, PATH_ANIM_DUR, STD_EASING]; - pathComponents.push(animPath); - - if(paths.region) { - let regStartPt = `${newXList[0]},${zeroLine}L`; - let regEndPt = `L${newXList.slice(-1)[0]}, ${zeroLine}`; - - const animRegion = [ - paths.region, - {d:"M" + regStartPt + pointsStr + regEndPt}, - PATH_ANIM_DUR, - STD_EASING - ]; - pathComponents.push(animRegion); - } - - return pathComponents; -} - -export function animatePathStr(oldPath, pathStr) { - return [oldPath, {d: pathStr}, UNIT_ANIM_DUR, STD_EASING]; -} diff --git a/node_modules/frappe-charts/src/js/utils/animation.js b/node_modules/frappe-charts/src/js/utils/animation.js deleted file mode 100644 index 19af5fe..0000000 --- a/node_modules/frappe-charts/src/js/utils/animation.js +++ /dev/null @@ -1,120 +0,0 @@ -// Leveraging SMIL Animations - -import { REPLACE_ALL_NEW_DUR } from './animate'; - -const EASING = { - ease: "0.25 0.1 0.25 1", - linear: "0 0 1 1", - // easein: "0.42 0 1 1", - easein: "0.1 0.8 0.2 1", - easeout: "0 0 0.58 1", - easeinout: "0.42 0 0.58 1" -}; - -function animateSVGElement(element, props, dur, easingType="linear", type=undefined, oldValues={}) { - - let animElement = element.cloneNode(true); - let newElement = element.cloneNode(true); - - for(var attributeName in props) { - let animateElement; - if(attributeName === 'transform') { - animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animateTransform"); - } else { - animateElement = document.createElementNS("http://www.w3.org/2000/svg", "animate"); - } - let currentValue = oldValues[attributeName] || element.getAttribute(attributeName); - let value = props[attributeName]; - - let animAttr = { - attributeName: attributeName, - from: currentValue, - to: value, - begin: "0s", - dur: dur/1000 + "s", - values: currentValue + ";" + value, - keySplines: EASING[easingType], - keyTimes: "0;1", - calcMode: "spline", - fill: 'freeze' - }; - - if(type) { - animAttr["type"] = type; - } - - for (var i in animAttr) { - animateElement.setAttribute(i, animAttr[i]); - } - - animElement.appendChild(animateElement); - - if(type) { - newElement.setAttribute(attributeName, `translate(${value})`); - } else { - newElement.setAttribute(attributeName, value); - } - } - - return [animElement, newElement]; -} - -export function transform(element, style) { // eslint-disable-line no-unused-vars - element.style.transform = style; - element.style.webkitTransform = style; - element.style.msTransform = style; - element.style.mozTransform = style; - element.style.oTransform = style; -} - -function animateSVG(svgContainer, elements) { - let newElements = []; - let animElements = []; - - elements.map(element => { - let unit = element[0]; - let parent = unit.parentNode; - - let animElement, newElement; - - element[0] = unit; - [animElement, newElement] = animateSVGElement(...element); - - newElements.push(newElement); - animElements.push([animElement, parent]); - - if (parent) { - parent.replaceChild(animElement, unit); - } - }); - - let animSvg = svgContainer.cloneNode(true); - - animElements.map((animElement, i) => { - if (animElement[1]) { - animElement[1].replaceChild(newElements[i], animElement[0]); - elements[i][0] = newElements[i]; - } - }); - - return animSvg; -} - -export function runSMILAnimation(parent, svgElement, elementsToAnimate) { - if(elementsToAnimate.length === 0) return; - - let animSvgElement = animateSVG(svgElement, elementsToAnimate); - if(svgElement.parentNode == parent) { - parent.removeChild(svgElement); - parent.appendChild(animSvgElement); - - } - - // Replace the new svgElement (data has already been replaced) - setTimeout(() => { - if(animSvgElement.parentNode == parent) { - parent.removeChild(animSvgElement); - parent.appendChild(svgElement); - } - }, REPLACE_ALL_NEW_DUR); -} diff --git a/node_modules/frappe-charts/src/js/utils/axis-chart-utils.js b/node_modules/frappe-charts/src/js/utils/axis-chart-utils.js deleted file mode 100644 index 42e7dd1..0000000 --- a/node_modules/frappe-charts/src/js/utils/axis-chart-utils.js +++ /dev/null @@ -1,129 +0,0 @@ -import { fillArray } from '../utils/helpers'; -import { DEFAULT_AXIS_CHART_TYPE, AXIS_DATASET_CHART_TYPES, DEFAULT_CHAR_WIDTH } from '../utils/constants'; - -export function dataPrep(data, type) { - data.labels = data.labels || []; - - let datasetLength = data.labels.length; - - // Datasets - let datasets = data.datasets; - let zeroArray = new Array(datasetLength).fill(0); - if(!datasets) { - // default - datasets = [{ - values: zeroArray - }]; - } - - datasets.map(d=> { - // Set values - if(!d.values) { - d.values = zeroArray; - } else { - // Check for non values - let vals = d.values; - vals = vals.map(val => (!isNaN(val) ? val : 0)); - - // Trim or extend - if(vals.length > datasetLength) { - vals = vals.slice(0, datasetLength); - } else { - vals = fillArray(vals, datasetLength - vals.length, 0); - } - d.values = vals; - } - - // Set type - if(!d.chartType ) { - if(!AXIS_DATASET_CHART_TYPES.includes(type)) type === DEFAULT_AXIS_CHART_TYPE; - d.chartType = type; - } - - }); - - // Markers - - // Regions - // data.yRegions = data.yRegions || []; - if(data.yRegions) { - data.yRegions.map(d => { - if(d.end < d.start) { - [d.start, d.end] = [d.end, d.start]; - } - }); - } - - return data; -} - -export function zeroDataPrep(realData) { - let datasetLength = realData.labels.length; - let zeroArray = new Array(datasetLength).fill(0); - - let zeroData = { - labels: realData.labels.slice(0, -1), - datasets: realData.datasets.map(d => { - return { - name: '', - values: zeroArray.slice(0, -1), - chartType: d.chartType - }; - }), - }; - - if(realData.yMarkers) { - zeroData.yMarkers = [ - { - value: 0, - label: '' - } - ]; - } - - if(realData.yRegions) { - zeroData.yRegions = [ - { - start: 0, - end: 0, - label: '' - } - ]; - } - - return zeroData; -} - -export function getShortenedLabels(chartWidth, labels=[], isSeries=true) { - let allowedSpace = chartWidth / labels.length; - if(allowedSpace <= 0) allowedSpace = 1; - let allowedLetters = allowedSpace / DEFAULT_CHAR_WIDTH; - - let seriesMultiple; - if(isSeries) { - // Find the maximum label length for spacing calculations - let maxLabelLength = Math.max(...labels.map(label => label.length)); - seriesMultiple = Math.ceil(maxLabelLength/allowedLetters); - } - - let calcLabels = labels.map((label, i) => { - label += ""; - if(label.length > allowedLetters) { - - if(!isSeries) { - if(allowedLetters-3 > 0) { - label = label.slice(0, allowedLetters-3) + " ..."; - } else { - label = label.slice(0, allowedLetters) + '..'; - } - } else { - if(i % seriesMultiple !== 0) { - label = ""; - } - } - } - return label; - }); - - return calcLabels; -} diff --git a/node_modules/frappe-charts/src/js/utils/colors.js b/node_modules/frappe-charts/src/js/utils/colors.js deleted file mode 100644 index b77b6e0..0000000 --- a/node_modules/frappe-charts/src/js/utils/colors.js +++ /dev/null @@ -1,53 +0,0 @@ -const PRESET_COLOR_MAP = { - 'light-blue': '#7cd6fd', - 'blue': '#5e64ff', - 'violet': '#743ee2', - 'red': '#ff5858', - 'orange': '#ffa00a', - 'yellow': '#feef72', - 'green': '#28a745', - 'light-green': '#98d85b', - 'purple': '#b554ff', - 'magenta': '#ffa3ef', - 'black': '#36114C', - 'grey': '#bdd3e6', - 'light-grey': '#f0f4f7', - 'dark-grey': '#b8c2cc' -}; - -function limitColor(r){ - if (r > 255) return 255; - else if (r < 0) return 0; - return r; -} - -export function lightenDarkenColor(color, amt) { - let col = getColor(color); - let usePound = false; - if (col[0] == "#") { - col = col.slice(1); - usePound = true; - } - let num = parseInt(col,16); - let r = limitColor((num >> 16) + amt); - let b = limitColor(((num >> 8) & 0x00FF) + amt); - let g = limitColor((num & 0x0000FF) + amt); - return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16); -} - -export function isValidColor(string) { - // https://stackoverflow.com/a/32685393 - let HEX_RE = /(^\s*)(#)((?:[A-Fa-f0-9]{3}){1,2})$/i; - let RGB_RE = /(^\s*)(rgb|hsl)(a?)[(]\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*,\s*([\d.]+\s*%?)\s*(?:,\s*([\d.]+)\s*)?[)]$/i; - return HEX_RE.test(string) || RGB_RE.test(string); -} - -export const getColor = (color) => { - // When RGB color, convert to hexadecimal (alpha value is omitted) - if((/rgb[a]{0,1}\([\d, ]+\)/gim).test(color)) { - return (/\D+(\d*)\D+(\d*)\D+(\d*)/gim).exec(color) - .map((x, i) => (i !== 0 ? Number(x).toString(16) : '#')) - .reduce((c, ch) => `${c}${ch}`); - } - return PRESET_COLOR_MAP[color] || color; -}; diff --git a/node_modules/frappe-charts/src/js/utils/constants.js b/node_modules/frappe-charts/src/js/utils/constants.js deleted file mode 100644 index 041cfaa..0000000 --- a/node_modules/frappe-charts/src/js/utils/constants.js +++ /dev/null @@ -1,107 +0,0 @@ -export const ALL_CHART_TYPES = ['line', 'scatter', 'bar', 'percentage', 'heatmap', 'pie']; - -export const COMPATIBLE_CHARTS = { - bar: ['line', 'scatter', 'percentage', 'pie'], - line: ['scatter', 'bar', 'percentage', 'pie'], - pie: ['line', 'scatter', 'percentage', 'bar'], - percentage: ['bar', 'line', 'scatter', 'pie'], - heatmap: [] -}; - -export const DATA_COLOR_DIVISIONS = { - bar: 'datasets', - line: 'datasets', - pie: 'labels', - percentage: 'labels', - heatmap: HEATMAP_DISTRIBUTION_SIZE -}; - -export const BASE_MEASURES = { - margins: { - top: 10, - bottom: 10, - left: 20, - right: 20 - }, - paddings: { - top: 20, - bottom: 40, - left: 30, - right: 10 - }, - - baseHeight: 240, - titleHeight: 20, - legendHeight: 30, - - titleFontSize: 12, -}; - -export function getTopOffset(m) { - return m.titleHeight + m.margins.top + m.paddings.top; -} - -export function getLeftOffset(m) { - return m.margins.left + m.paddings.left; -} - -export function getExtraHeight(m) { - let totalExtraHeight = m.margins.top + m.margins.bottom - + m.paddings.top + m.paddings.bottom - + m.titleHeight + m.legendHeight; - return totalExtraHeight; -} - -export function getExtraWidth(m) { - let totalExtraWidth = m.margins.left + m.margins.right - + m.paddings.left + m.paddings.right; - - return totalExtraWidth; -} - -export const INIT_CHART_UPDATE_TIMEOUT = 700; -export const CHART_POST_ANIMATE_TIMEOUT = 400; - -export const DEFAULT_AXIS_CHART_TYPE = 'line'; -export const AXIS_DATASET_CHART_TYPES = ['line', 'bar']; - -export const AXIS_LEGEND_BAR_SIZE = 100; - -export const BAR_CHART_SPACE_RATIO = 0.5; -export const MIN_BAR_PERCENT_HEIGHT = 0.00; - -export const LINE_CHART_DOT_SIZE = 4; -export const DOT_OVERLAY_SIZE_INCR = 4; - -export const PERCENTAGE_BAR_DEFAULT_HEIGHT = 20; -export const PERCENTAGE_BAR_DEFAULT_DEPTH = 2; - -// Fixed 5-color theme, -// More colors are difficult to parse visually -export const HEATMAP_DISTRIBUTION_SIZE = 5; - -export const HEATMAP_SQUARE_SIZE = 10; -export const HEATMAP_GUTTER_SIZE = 2; - -export const DEFAULT_CHAR_WIDTH = 7; - -export const TOOLTIP_POINTER_TRIANGLE_HEIGHT = 5; - -const DEFAULT_CHART_COLORS = ['light-blue', 'blue', 'violet', 'red', 'orange', - 'yellow', 'green', 'light-green', 'purple', 'magenta', 'light-grey', 'dark-grey']; -const HEATMAP_COLORS_GREEN = ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127']; -export const HEATMAP_COLORS_BLUE = ['#ebedf0', '#c0ddf9', '#73b3f3', '#3886e1', '#17459e']; -export const HEATMAP_COLORS_YELLOW = ['#ebedf0', '#fdf436', '#ffc700', '#ff9100', '#06001c']; - -export const DEFAULT_COLORS = { - bar: DEFAULT_CHART_COLORS, - line: DEFAULT_CHART_COLORS, - pie: DEFAULT_CHART_COLORS, - percentage: DEFAULT_CHART_COLORS, - heatmap: HEATMAP_COLORS_GREEN, - donut: DEFAULT_CHART_COLORS -}; - -// Universal constants -export const ANGLE_RATIO = Math.PI / 180; -export const FULL_ANGLE = 360; diff --git a/node_modules/frappe-charts/src/js/utils/date-utils.js b/node_modules/frappe-charts/src/js/utils/date-utils.js deleted file mode 100644 index d0c8d80..0000000 --- a/node_modules/frappe-charts/src/js/utils/date-utils.js +++ /dev/null @@ -1,90 +0,0 @@ -// Playing around with dates - -export const NO_OF_YEAR_MONTHS = 12; -export const NO_OF_DAYS_IN_WEEK = 7; -export const DAYS_IN_YEAR = 375; -export const NO_OF_MILLIS = 1000; -export const SEC_IN_DAY = 86400; - -export const MONTH_NAMES = ["January", "February", "March", "April", "May", - "June", "July", "August", "September", "October", "November", "December"]; -export const MONTH_NAMES_SHORT = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; - -export const DAY_NAMES_SHORT = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; -export const DAY_NAMES = ["Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday"]; - -// https://stackoverflow.com/a/11252167/6495043 -function treatAsUtc(date) { - let result = new Date(date); - result.setMinutes(result.getMinutes() - result.getTimezoneOffset()); - return result; -} - -export function getYyyyMmDd(date) { - let dd = date.getDate(); - let mm = date.getMonth() + 1; // getMonth() is zero-based - return [ - date.getFullYear(), - (mm>9 ? '' : '0') + mm, - (dd>9 ? '' : '0') + dd - ].join('-'); -} - -export function clone(date) { - return new Date(date.getTime()); -} - -export function timestampSec(date) { - return date.getTime()/NO_OF_MILLIS; -} - -export function timestampToMidnight(timestamp, roundAhead = false) { - let midnightTs = Math.floor(timestamp - (timestamp % SEC_IN_DAY)); - if(roundAhead) { - return midnightTs + SEC_IN_DAY; - } - return midnightTs; -} - -// export function getMonthsBetween(startDate, endDate) {} - -export function getWeeksBetween(startDate, endDate) { - let weekStartDate = setDayToSunday(startDate); - return Math.ceil(getDaysBetween(weekStartDate, endDate) / NO_OF_DAYS_IN_WEEK); -} - -export function getDaysBetween(startDate, endDate) { - let millisecondsPerDay = SEC_IN_DAY * NO_OF_MILLIS; - return (treatAsUtc(endDate) - treatAsUtc(startDate)) / millisecondsPerDay; -} - -export function areInSameMonth(startDate, endDate) { - return startDate.getMonth() === endDate.getMonth() - && startDate.getFullYear() === endDate.getFullYear(); -} - -export function getMonthName(i, short=false) { - let monthName = MONTH_NAMES[i]; - return short ? monthName.slice(0, 3) : monthName; -} - -export function getLastDateInMonth (month, year) { - return new Date(year, month + 1, 0); // 0: last day in previous month -} - -// mutates -export function setDayToSunday(date) { - let newDate = clone(date); - const day = newDate.getDay(); - if(day !== 0) { - addDays(newDate, (-1) * day); - } - return newDate; -} - -// mutates -export function addDays(date, numberOfDays) { - date.setDate(date.getDate() + numberOfDays); -} diff --git a/node_modules/frappe-charts/src/js/utils/dom.js b/node_modules/frappe-charts/src/js/utils/dom.js deleted file mode 100644 index 91cd2a7..0000000 --- a/node_modules/frappe-charts/src/js/utils/dom.js +++ /dev/null @@ -1,137 +0,0 @@ -export function $(expr, con) { - return typeof expr === "string"? (con || document).querySelector(expr) : expr || null; -} - -export function findNodeIndex(node) -{ - var i = 0; - while (node.previousSibling) { - node = node.previousSibling; - i++; - } - return i; -} - -$.create = (tag, o) => { - var element = document.createElement(tag); - - for (var i in o) { - var val = o[i]; - - if (i === "inside") { - $(val).appendChild(element); - } - else if (i === "around") { - var ref = $(val); - ref.parentNode.insertBefore(element, ref); - element.appendChild(ref); - - } else if (i === "styles") { - if(typeof val === "object") { - Object.keys(val).map(prop => { - element.style[prop] = val[prop]; - }); - } - } else if (i in element ) { - element[i] = val; - } - else { - element.setAttribute(i, val); - } - } - - return element; -}; - -export function getOffset(element) { - let rect = element.getBoundingClientRect(); - return { - // https://stackoverflow.com/a/7436602/6495043 - // rect.top varies with scroll, so we add whatever has been - // scrolled to it to get absolute distance from actual page top - top: rect.top + (document.documentElement.scrollTop || document.body.scrollTop), - left: rect.left + (document.documentElement.scrollLeft || document.body.scrollLeft) - }; -} - -// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/offsetParent -// an element's offsetParent property will return null whenever it, or any of its parents, -// is hidden via the display style property. -export function isHidden(el) { - return (el.offsetParent === null); -} - -export function isElementInViewport(el) { - // Although straightforward: https://stackoverflow.com/a/7557433/6495043 - var rect = el.getBoundingClientRect(); - - return ( - rect.top >= 0 && - rect.left >= 0 && - rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && /*or $(window).height() */ - rect.right <= (window.innerWidth || document.documentElement.clientWidth) /*or $(window).width() */ - ); -} - -export function getElementContentWidth(element) { - var styles = window.getComputedStyle(element); - var padding = parseFloat(styles.paddingLeft) + - parseFloat(styles.paddingRight); - - return element.clientWidth - padding; -} - -export function bind(element, o){ - if (element) { - for (var event in o) { - var callback = o[event]; - - event.split(/\s+/).forEach(function (event) { - element.addEventListener(event, callback); - }); - } - } -} - -export function unbind(element, o){ - if (element) { - for (var event in o) { - var callback = o[event]; - - event.split(/\s+/).forEach(function(event) { - element.removeEventListener(event, callback); - }); - } - } -} - -export function fire(target, type, properties) { - var evt = document.createEvent("HTMLEvents"); - - evt.initEvent(type, true, true ); - - for (var j in properties) { - evt[j] = properties[j]; - } - - return target.dispatchEvent(evt); -} - -// https://css-tricks.com/snippets/javascript/loop-queryselectorall-matches/ -export function forEachNode(nodeList, callback, scope) { - if(!nodeList) return; - for (var i = 0; i < nodeList.length; i++) { - callback.call(scope, nodeList[i], i); - } -} - -export function activate($parent, $child, commonClass, activeClass='active', index = -1) { - let $children = $parent.querySelectorAll(`.${commonClass}.${activeClass}`); - - forEachNode($children, (node, i) => { - if(index >= 0 && i <= index) return; - node.classList.remove(activeClass); - }); - - $child.classList.add(activeClass); -} diff --git a/node_modules/frappe-charts/src/js/utils/draw-utils.js b/node_modules/frappe-charts/src/js/utils/draw-utils.js deleted file mode 100644 index c4a81aa..0000000 --- a/node_modules/frappe-charts/src/js/utils/draw-utils.js +++ /dev/null @@ -1,99 +0,0 @@ -import { fillArray } from './helpers'; - -export function getBarHeightAndYAttr(yTop, zeroLine) { - let height, y; - if (yTop <= zeroLine) { - height = zeroLine - yTop; - y = yTop; - } else { - height = yTop - zeroLine; - y = zeroLine; - } - - return [height, y]; -} - -export function equilizeNoOfElements(array1, array2, - extraCount = array2.length - array1.length) { - - // Doesn't work if either has zero elements. - if(extraCount > 0) { - array1 = fillArray(array1, extraCount); - } else { - array2 = fillArray(array2, extraCount); - } - return [array1, array2]; -} - -export function truncateString(txt, len) { - if (!txt) { - return; - } - if (txt.length > len) { - return txt.slice(0, len-3) + '...'; - } else { - return txt; - } -} - -export function shortenLargeNumber(label) { - let number; - if (typeof label === 'number') number = label; - else if (typeof label === 'string') { - number = Number(label); - if (Number.isNaN(number)) return label; - } - - // Using absolute since log wont work for negative numbers - let p = Math.floor(Math.log10(Math.abs(number))); - if (p <= 2) return number; // Return as is for a 3 digit number of less - let l = Math.floor(p / 3); - let shortened = (Math.pow(10, p - l * 3) * +(number / Math.pow(10, p)).toFixed(1)); - - // Correct for floating point error upto 2 decimal places - return Math.round(shortened*100)/100 + ' ' + ['', 'K', 'M', 'B', 'T'][l]; -} - -// cubic bezier curve calculation (from example by François Romain) -export function getSplineCurvePointsStr(xList, yList) { - - let points=[]; - for(let i=0;i { - let lengthX = pointB[0] - pointA[0]; - let lengthY = pointB[1] - pointA[1]; - return { - length: Math.sqrt(Math.pow(lengthX, 2) + Math.pow(lengthY, 2)), - angle: Math.atan2(lengthY, lengthX) - }; - }; - - let controlPoint = (current, previous, next, reverse) => { - let p = previous || current; - let n = next || current; - let o = line(p, n); - let angle = o.angle + (reverse ? Math.PI : 0); - let length = o.length * smoothing; - let x = current[0] + Math.cos(angle) * length; - let y = current[1] + Math.sin(angle) * length; - return [x, y]; - }; - - let bezierCommand = (point, i, a) => { - let cps = controlPoint(a[i - 1], a[i - 2], point); - let cpe = controlPoint(point, a[i - 1], a[i + 1], true); - return `C ${cps[0]},${cps[1]} ${cpe[0]},${cpe[1]} ${point[0]},${point[1]}`; - }; - - let pointStr = (points, command) => { - return points.reduce((acc, point, i, a) => i === 0 - ? `${point[0]},${point[1]}` - : `${acc} ${command(point, i, a)}`, ''); - }; - - return pointStr(points, bezierCommand); -} diff --git a/node_modules/frappe-charts/src/js/utils/draw.js b/node_modules/frappe-charts/src/js/utils/draw.js deleted file mode 100644 index 8466a27..0000000 --- a/node_modules/frappe-charts/src/js/utils/draw.js +++ /dev/null @@ -1,731 +0,0 @@ -import { getBarHeightAndYAttr, truncateString, shortenLargeNumber, getSplineCurvePointsStr } from './draw-utils'; -import { getStringWidth, isValidNumber } from './helpers'; -import { DOT_OVERLAY_SIZE_INCR, PERCENTAGE_BAR_DEFAULT_DEPTH } from './constants'; -import { lightenDarkenColor } from './colors'; - -export const AXIS_TICK_LENGTH = 6; -const LABEL_MARGIN = 4; -const LABEL_MAX_CHARS = 15; -export const FONT_SIZE = 10; -const BASE_LINE_COLOR = '#dadada'; -const FONT_FILL = '#555b51'; - -function $(expr, con) { - return typeof expr === "string"? (con || document).querySelector(expr) : expr || null; -} - -export function createSVG(tag, o) { - var element = document.createElementNS("http://www.w3.org/2000/svg", tag); - - for (var i in o) { - var val = o[i]; - - if (i === "inside") { - $(val).appendChild(element); - } - else if (i === "around") { - var ref = $(val); - ref.parentNode.insertBefore(element, ref); - element.appendChild(ref); - - } else if (i === "styles") { - if(typeof val === "object") { - Object.keys(val).map(prop => { - element.style[prop] = val[prop]; - }); - } - } else { - if(i === "className") { i = "class"; } - if(i === "innerHTML") { - element['textContent'] = val; - } else { - element.setAttribute(i, val); - } - } - } - - return element; -} - -function renderVerticalGradient(svgDefElem, gradientId) { - return createSVG('linearGradient', { - inside: svgDefElem, - id: gradientId, - x1: 0, - x2: 0, - y1: 0, - y2: 1 - }); -} - -function setGradientStop(gradElem, offset, color, opacity) { - return createSVG('stop', { - 'inside': gradElem, - 'style': `stop-color: ${color}`, - 'offset': offset, - 'stop-opacity': opacity - }); -} - -export function makeSVGContainer(parent, className, width, height) { - return createSVG('svg', { - className: className, - inside: parent, - width: width, - height: height - }); -} - -export function makeSVGDefs(svgContainer) { - return createSVG('defs', { - inside: svgContainer, - }); -} - -export function makeSVGGroup(className, transform='', parent=undefined) { - let args = { - className: className, - transform: transform - }; - if(parent) args.inside = parent; - return createSVG('g', args); -} - -export function wrapInSVGGroup(elements, className='') { - let g = createSVG('g', { - className: className - }); - elements.forEach(e => g.appendChild(e)); - return g; -} - -export function makePath(pathStr, className='', stroke='none', fill='none', strokeWidth=2) { - return createSVG('path', { - className: className, - d: pathStr, - styles: { - stroke: stroke, - fill: fill, - 'stroke-width': strokeWidth - } - }); -} - -export function makeArcPathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ - let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; - let [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y]; - return `M${center.x} ${center.y} - L${arcStartX} ${arcStartY} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${arcEndY} z`; -} - -export function makeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ - let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; - let [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, center.y * 2, center.y + endPosition.y]; - return `M${center.x} ${center.y} - L${arcStartX} ${arcStartY} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${midArc} z - L${arcStartX} ${midArc} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${arcEndY} z`; -} - -export function makeArcStrokePathStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ - let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; - let [arcEndX, arcEndY] = [center.x + endPosition.x, center.y + endPosition.y]; - - return `M${arcStartX} ${arcStartY} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${arcEndY}`; -} - -export function makeStrokeCircleStr(startPosition, endPosition, center, radius, clockWise=1, largeArc=0){ - let [arcStartX, arcStartY] = [center.x + startPosition.x, center.y + startPosition.y]; - let [arcEndX, midArc, arcEndY] = [center.x + endPosition.x, radius * 2 + arcStartY, center.y + startPosition.y]; - - return `M${arcStartX} ${arcStartY} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${midArc} - M${arcStartX} ${midArc} - A ${radius} ${radius} 0 ${largeArc} ${clockWise ? 1 : 0} - ${arcEndX} ${arcEndY}`; -} - -export function makeGradient(svgDefElem, color, lighter = false) { - let gradientId ='path-fill-gradient' + '-' + color + '-' +(lighter ? 'lighter' : 'default'); - let gradientDef = renderVerticalGradient(svgDefElem, gradientId); - let opacities = [1, 0.6, 0.2]; - if(lighter) { - opacities = [0.4, 0.2, 0]; - } - - setGradientStop(gradientDef, "0%", color, opacities[0]); - setGradientStop(gradientDef, "50%", color, opacities[1]); - setGradientStop(gradientDef, "100%", color, opacities[2]); - - return gradientId; -} - -export function percentageBar(x, y, width, height, - depth=PERCENTAGE_BAR_DEFAULT_DEPTH, fill='none') { - - let args = { - className: 'percentage-bar', - x: x, - y: y, - width: width, - height: height, - fill: fill, - styles: { - 'stroke': lightenDarkenColor(fill, -25), - // Diabolically good: https://stackoverflow.com/a/9000859 - // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dasharray - 'stroke-dasharray': `0, ${height + width}, ${width}, ${height}`, - 'stroke-width': depth - }, - }; - - return createSVG("rect", args); -} - -export function heatSquare(className, x, y, size, radius, fill='none', data={}) { - let args = { - className: className, - x: x, - y: y, - width: size, - height: size, - rx: radius, - fill: fill - }; - - Object.keys(data).map(key => { - args[key] = data[key]; - }); - - return createSVG("rect", args); -} - -export function legendBar(x, y, size, fill='none', label, truncate=false) { - label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label; - - let args = { - className: 'legend-bar', - x: 0, - y: 0, - width: size, - height: '2px', - fill: fill - }; - let text = createSVG('text', { - className: 'legend-dataset-text', - x: 0, - y: 0, - dy: (FONT_SIZE * 2) + 'px', - 'font-size': (FONT_SIZE * 1.2) + 'px', - 'text-anchor': 'start', - fill: FONT_FILL, - innerHTML: label - }); - - let group = createSVG('g', { - transform: `translate(${x}, ${y})` - }); - group.appendChild(createSVG("rect", args)); - group.appendChild(text); - - return group; -} - -export function legendDot(x, y, size, fill='none', label, truncate=false) { - label = truncate ? truncateString(label, LABEL_MAX_CHARS) : label; - - let args = { - className: 'legend-dot', - cx: 0, - cy: 0, - r: size, - fill: fill - }; - let text = createSVG('text', { - className: 'legend-dataset-text', - x: 0, - y: 0, - dx: (FONT_SIZE) + 'px', - dy: (FONT_SIZE/3) + 'px', - 'font-size': (FONT_SIZE * 1.2) + 'px', - 'text-anchor': 'start', - fill: FONT_FILL, - innerHTML: label - }); - - let group = createSVG('g', { - transform: `translate(${x}, ${y})` - }); - group.appendChild(createSVG("circle", args)); - group.appendChild(text); - - return group; -} - -export function makeText(className, x, y, content, options = {}) { - let fontSize = options.fontSize || FONT_SIZE; - let dy = options.dy !== undefined ? options.dy : (fontSize / 2); - let fill = options.fill || FONT_FILL; - let textAnchor = options.textAnchor || 'start'; - return createSVG('text', { - className: className, - x: x, - y: y, - dy: dy + 'px', - 'font-size': fontSize + 'px', - fill: fill, - 'text-anchor': textAnchor, - innerHTML: content - }); -} - -function makeVertLine(x, label, y1, y2, options={}) { - if(!options.stroke) options.stroke = BASE_LINE_COLOR; - let l = createSVG('line', { - className: 'line-vertical ' + options.className, - x1: 0, - x2: 0, - y1: y1, - y2: y2, - styles: { - stroke: options.stroke - } - }); - - let text = createSVG('text', { - x: 0, - y: y1 > y2 ? y1 + LABEL_MARGIN : y1 - LABEL_MARGIN - FONT_SIZE, - dy: FONT_SIZE + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': 'middle', - innerHTML: label + "" - }); - - let line = createSVG('g', { - transform: `translate(${ x }, 0)` - }); - - line.appendChild(l); - line.appendChild(text); - - return line; -} - -function makeHoriLine(y, label, x1, x2, options={}) { - if(!options.stroke) options.stroke = BASE_LINE_COLOR; - if(!options.lineType) options.lineType = ''; - if (options.shortenNumbers) label = shortenLargeNumber(label); - - let className = 'line-horizontal ' + options.className + - (options.lineType === "dashed" ? "dashed": ""); - - let l = createSVG('line', { - className: className, - x1: x1, - x2: x2, - y1: 0, - y2: 0, - styles: { - stroke: options.stroke - } - }); - - let text = createSVG('text', { - x: x1 < x2 ? x1 - LABEL_MARGIN : x1 + LABEL_MARGIN, - y: 0, - dy: (FONT_SIZE / 2 - 2) + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': x1 < x2 ? 'end' : 'start', - innerHTML: label+"" - }); - - let line = createSVG('g', { - transform: `translate(0, ${y})`, - 'stroke-opacity': 1 - }); - - if(text === 0 || text === '0') { - line.style.stroke = "rgba(27, 31, 35, 0.6)"; - } - - line.appendChild(l); - line.appendChild(text); - - return line; -} - -export function yLine(y, label, width, options={}) { - if (!isValidNumber(y)) y = 0; - - if(!options.pos) options.pos = 'left'; - if(!options.offset) options.offset = 0; - if(!options.mode) options.mode = 'span'; - if(!options.stroke) options.stroke = BASE_LINE_COLOR; - if(!options.className) options.className = ''; - - let x1 = -1 * AXIS_TICK_LENGTH; - let x2 = options.mode === 'span' ? width + AXIS_TICK_LENGTH : 0; - - if(options.mode === 'tick' && options.pos === 'right') { - x1 = width + AXIS_TICK_LENGTH; - x2 = width; - } - - // let offset = options.pos === 'left' ? -1 * options.offset : options.offset; - - x1 += options.offset; - x2 += options.offset; - - return makeHoriLine(y, label, x1, x2, { - stroke: options.stroke, - className: options.className, - lineType: options.lineType, - shortenNumbers: options.shortenNumbers - }); -} - -export function xLine(x, label, height, options={}) { - if (!isValidNumber(x)) x = 0; - - if(!options.pos) options.pos = 'bottom'; - if(!options.offset) options.offset = 0; - if(!options.mode) options.mode = 'span'; - if(!options.stroke) options.stroke = BASE_LINE_COLOR; - if(!options.className) options.className = ''; - - // Draw X axis line in span/tick mode with optional label - // y2(span) - // | - // | - // x line | - // | - // | - // ---------------------+-- y2(tick) - // | - // y1 - - let y1 = height + AXIS_TICK_LENGTH; - let y2 = options.mode === 'span' ? -1 * AXIS_TICK_LENGTH : height; - - if(options.mode === 'tick' && options.pos === 'top') { - // top axis ticks - y1 = -1 * AXIS_TICK_LENGTH; - y2 = 0; - } - - return makeVertLine(x, label, y1, y2, { - stroke: options.stroke, - className: options.className, - lineType: options.lineType - }); -} - -export function yMarker(y, label, width, options={}) { - if(!options.labelPos) options.labelPos = 'right'; - let x = options.labelPos === 'left' ? LABEL_MARGIN - : width - getStringWidth(label, 5) - LABEL_MARGIN; - - let labelSvg = createSVG('text', { - className: 'chart-label', - x: x, - y: 0, - dy: (FONT_SIZE / -2) + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': 'start', - innerHTML: label+"" - }); - - let line = makeHoriLine(y, '', 0, width, { - stroke: options.stroke || BASE_LINE_COLOR, - className: options.className || '', - lineType: options.lineType - }); - - line.appendChild(labelSvg); - - return line; -} - -export function yRegion(y1, y2, width, label, options={}) { - // return a group - let height = y1 - y2; - - let rect = createSVG('rect', { - className: `bar mini`, // remove class - styles: { - fill: `rgba(228, 234, 239, 0.49)`, - stroke: BASE_LINE_COLOR, - 'stroke-dasharray': `${width}, ${height}` - }, - // 'data-point-index': index, - x: 0, - y: 0, - width: width, - height: height - }); - - if(!options.labelPos) options.labelPos = 'right'; - let x = options.labelPos === 'left' ? LABEL_MARGIN - : width - getStringWidth(label+"", 4.5) - LABEL_MARGIN; - - let labelSvg = createSVG('text', { - className: 'chart-label', - x: x, - y: 0, - dy: (FONT_SIZE / -2) + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': 'start', - innerHTML: label+"" - }); - - let region = createSVG('g', { - transform: `translate(0, ${y2})` - }); - - region.appendChild(rect); - region.appendChild(labelSvg); - - return region; -} - -export function datasetBar(x, yTop, width, color, label='', index=0, offset=0, meta={}) { - let [height, y] = getBarHeightAndYAttr(yTop, meta.zeroLine); - y -= offset; - - if(height === 0) { - height = meta.minHeight; - y -= meta.minHeight; - } - - // Preprocess numbers to avoid svg building errors - if (!isValidNumber(x)) x = 0; - if (!isValidNumber(y)) y = 0; - if (!isValidNumber(height, true)) height = 0; - if (!isValidNumber(width, true)) width = 0; - - let rect = createSVG('rect', { - className: `bar mini`, - style: `fill: ${color}`, - 'data-point-index': index, - x: x, - y: y, - width: width, - height: height - }); - - label += ""; - - if(!label && !label.length) { - return rect; - } else { - rect.setAttribute('y', 0); - rect.setAttribute('x', 0); - let text = createSVG('text', { - className: 'data-point-value', - x: width/2, - y: 0, - dy: (FONT_SIZE / 2 * -1) + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': 'middle', - innerHTML: label - }); - - let group = createSVG('g', { - 'data-point-index': index, - transform: `translate(${x}, ${y})` - }); - group.appendChild(rect); - group.appendChild(text); - - return group; - } -} - -export function datasetDot(x, y, radius, color, label='', index=0) { - let dot = createSVG('circle', { - style: `fill: ${color}`, - 'data-point-index': index, - cx: x, - cy: y, - r: radius - }); - - label += ""; - - if(!label && !label.length) { - return dot; - } else { - dot.setAttribute('cy', 0); - dot.setAttribute('cx', 0); - - let text = createSVG('text', { - className: 'data-point-value', - x: 0, - y: 0, - dy: (FONT_SIZE / 2 * -1 - radius) + 'px', - 'font-size': FONT_SIZE + 'px', - 'text-anchor': 'middle', - innerHTML: label - }); - - let group = createSVG('g', { - 'data-point-index': index, - transform: `translate(${x}, ${y})` - }); - group.appendChild(dot); - group.appendChild(text); - - return group; - } -} - -export function getPaths(xList, yList, color, options={}, meta={}) { - let pointsList = yList.map((y, i) => (xList[i] + ',' + y)); - let pointsStr = pointsList.join("L"); - - // Spline - if (options.spline) - pointsStr = getSplineCurvePointsStr(xList, yList); - - let path = makePath("M"+pointsStr, 'line-graph-path', color); - - // HeatLine - if(options.heatline) { - let gradient_id = makeGradient(meta.svgDefs, color); - path.style.stroke = `url(#${gradient_id})`; - } - - let paths = { - path: path - }; - - // Region - if(options.regionFill) { - let gradient_id_region = makeGradient(meta.svgDefs, color, true); - - let pathStr = "M" + `${xList[0]},${meta.zeroLine}L` + pointsStr + `L${xList.slice(-1)[0]},${meta.zeroLine}`; - paths.region = makePath(pathStr, `region-fill`, 'none', `url(#${gradient_id_region})`); - } - - return paths; -} - -export let makeOverlay = { - 'bar': (unit) => { - let transformValue; - if(unit.nodeName !== 'rect') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let overlay = unit.cloneNode(); - overlay.style.fill = '#000000'; - overlay.style.opacity = '0.4'; - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - return overlay; - }, - - 'dot': (unit) => { - let transformValue; - if(unit.nodeName !== 'circle') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let overlay = unit.cloneNode(); - let radius = unit.getAttribute('r'); - let fill = unit.getAttribute('fill'); - overlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR); - overlay.setAttribute('fill', fill); - overlay.style.opacity = '0.6'; - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - return overlay; - }, - - 'heat_square': (unit) => { - let transformValue; - if(unit.nodeName !== 'circle') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let overlay = unit.cloneNode(); - let radius = unit.getAttribute('r'); - let fill = unit.getAttribute('fill'); - overlay.setAttribute('r', parseInt(radius) + DOT_OVERLAY_SIZE_INCR); - overlay.setAttribute('fill', fill); - overlay.style.opacity = '0.6'; - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - return overlay; - } -}; - -export let updateOverlay = { - 'bar': (unit, overlay) => { - let transformValue; - if(unit.nodeName !== 'rect') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let attributes = ['x', 'y', 'width', 'height']; - Object.values(unit.attributes) - .filter(attr => attributes.includes(attr.name) && attr.specified) - .map(attr => { - overlay.setAttribute(attr.name, attr.nodeValue); - }); - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - }, - - 'dot': (unit, overlay) => { - let transformValue; - if(unit.nodeName !== 'circle') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let attributes = ['cx', 'cy']; - Object.values(unit.attributes) - .filter(attr => attributes.includes(attr.name) && attr.specified) - .map(attr => { - overlay.setAttribute(attr.name, attr.nodeValue); - }); - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - }, - - 'heat_square': (unit, overlay) => { - let transformValue; - if(unit.nodeName !== 'circle') { - transformValue = unit.getAttribute('transform'); - unit = unit.childNodes[0]; - } - let attributes = ['cx', 'cy']; - Object.values(unit.attributes) - .filter(attr => attributes.includes(attr.name) && attr.specified) - .map(attr => { - overlay.setAttribute(attr.name, attr.nodeValue); - }); - - if(transformValue) { - overlay.setAttribute('transform', transformValue); - } - }, -}; diff --git a/node_modules/frappe-charts/src/js/utils/export.js b/node_modules/frappe-charts/src/js/utils/export.js deleted file mode 100644 index 842dc3d..0000000 --- a/node_modules/frappe-charts/src/js/utils/export.js +++ /dev/null @@ -1,33 +0,0 @@ -import { $ } from '../utils/dom'; -import { CSSTEXT } from '../../css/chartsCss'; - -export function downloadFile(filename, data) { - var a = document.createElement('a'); - a.style = "display: none"; - var blob = new Blob(data, {type: "image/svg+xml; charset=utf-8"}); - var url = window.URL.createObjectURL(blob); - a.href = url; - a.download = filename; - document.body.appendChild(a); - a.click(); - setTimeout(function(){ - document.body.removeChild(a); - window.URL.revokeObjectURL(url); - }, 300); -} - -export function prepareForExport(svg) { - let clone = svg.cloneNode(true); - clone.classList.add('chart-container'); - clone.setAttribute('xmlns', "http://www.w3.org/2000/svg"); - clone.setAttribute('xmlns:xlink', "http://www.w3.org/1999/xlink"); - let styleEl = $.create('style', { - 'innerHTML': CSSTEXT - }); - clone.insertBefore(styleEl, clone.firstChild); - - let container = $.create('div'); - container.appendChild(clone); - - return container.innerHTML; -} diff --git a/node_modules/frappe-charts/src/js/utils/helpers.js b/node_modules/frappe-charts/src/js/utils/helpers.js deleted file mode 100644 index d1493f7..0000000 --- a/node_modules/frappe-charts/src/js/utils/helpers.js +++ /dev/null @@ -1,143 +0,0 @@ -import { ANGLE_RATIO } from './constants'; - -/** - * Returns the value of a number upto 2 decimal places. - * @param {Number} d Any number - */ -export function floatTwo(d) { - return parseFloat(d.toFixed(2)); -} - -/** - * Returns whether or not two given arrays are equal. - * @param {Array} arr1 First array - * @param {Array} arr2 Second array - */ -export function arraysEqual(arr1, arr2) { - if(arr1.length !== arr2.length) return false; - let areEqual = true; - arr1.map((d, i) => { - if(arr2[i] !== d) areEqual = false; - }); - return areEqual; -} - -/** - * Shuffles array in place. ES6 version - * @param {Array} array An array containing the items. - */ -export function shuffle(array) { - // Awesomeness: https://bost.ocks.org/mike/shuffle/ - // https://stackoverflow.com/a/2450976/6495043 - // https://stackoverflow.com/questions/6274339/how-can-i-shuffle-an-array?noredirect=1&lq=1 - - for (let i = array.length - 1; i > 0; i--) { - let j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; - } - - return array; -} - -/** - * Fill an array with extra points - * @param {Array} array Array - * @param {Number} count number of filler elements - * @param {Object} element element to fill with - * @param {Boolean} start fill at start? - */ -export function fillArray(array, count, element, start=false) { - if(!element) { - element = start ? array[0] : array[array.length - 1]; - } - let fillerArray = new Array(Math.abs(count)).fill(element); - array = start ? fillerArray.concat(array) : array.concat(fillerArray); - return array; -} - -/** - * Returns pixel width of string. - * @param {String} string - * @param {Number} charWidth Width of single char in pixels - */ -export function getStringWidth(string, charWidth) { - return (string+"").length * charWidth; -} - -export function bindChange(obj, getFn, setFn) { - return new Proxy(obj, { - set: function(target, prop, value) { - setFn(); - return Reflect.set(target, prop, value); - }, - get: function(target, prop) { - getFn(); - return Reflect.get(target, prop); - } - }); -} - -// https://stackoverflow.com/a/29325222 -export function getRandomBias(min, max, bias, influence) { - const range = max - min; - const biasValue = range * bias + min; - var rnd = Math.random() * range + min, // random in range - mix = Math.random() * influence; // random mixer - return rnd * (1 - mix) + biasValue * mix; // mix full range and bias -} - -export function getPositionByAngle(angle, radius) { - return { - x: Math.sin(angle * ANGLE_RATIO) * radius, - y: Math.cos(angle * ANGLE_RATIO) * radius, - }; -} - -/** - * Check if a number is valid for svg attributes - * @param {object} candidate Candidate to test - * @param {Boolean} nonNegative flag to treat negative number as invalid - */ -export function isValidNumber(candidate, nonNegative=false) { - if (Number.isNaN(candidate)) return false; - else if (candidate === undefined) return false; - else if (!Number.isFinite(candidate)) return false; - else if (nonNegative && candidate < 0) return false; - else return true; -} - -/** - * Round a number to the closes precision, max max precision 4 - * @param {Number} d Any Number - */ -export function round(d) { - // https://floating-point-gui.de/ - // https://www.jacklmoore.com/notes/rounding-in-javascript/ - return Number(Math.round(d + 'e4') + 'e-4'); -} - -/** - * Creates a deep clone of an object - * @param {Object} candidate Any Object - */ - export function deepClone(candidate) { - let cloned, value, key; - - if (candidate instanceof Date) { - return new Date(candidate.getTime()); - } - - if (typeof candidate !== "object" || candidate === null) { - return candidate; - } - - cloned = Array.isArray(candidate) ? [] : {}; - - for (key in candidate) { - value = candidate[key]; - - cloned[key] = deepClone(value); - } - - return cloned; - } \ No newline at end of file diff --git a/node_modules/frappe-charts/src/js/utils/intervals.js b/node_modules/frappe-charts/src/js/utils/intervals.js deleted file mode 100644 index 6218117..0000000 --- a/node_modules/frappe-charts/src/js/utils/intervals.js +++ /dev/null @@ -1,239 +0,0 @@ -import { floatTwo } from './helpers'; - -function normalize(x) { - // Calculates mantissa and exponent of a number - // Returns normalized number and exponent - // https://stackoverflow.com/q/9383593/6495043 - - if(x===0) { - return [0, 0]; - } - if(isNaN(x)) { - return {mantissa: -6755399441055744, exponent: 972}; - } - var sig = x > 0 ? 1 : -1; - if(!isFinite(x)) { - return {mantissa: sig * 4503599627370496, exponent: 972}; - } - - x = Math.abs(x); - var exp = Math.floor(Math.log10(x)); - var man = x/Math.pow(10, exp); - - return [sig * man, exp]; -} - -function getChartRangeIntervals(max, min=0) { - let upperBound = Math.ceil(max); - let lowerBound = Math.floor(min); - let range = upperBound - lowerBound; - - let noOfParts = range; - let partSize = 1; - - // To avoid too many partitions - if(range > 5) { - if(range % 2 !== 0) { - upperBound++; - // Recalc range - range = upperBound - lowerBound; - } - noOfParts = range/2; - partSize = 2; - } - - // Special case: 1 and 2 - if(range <= 2) { - noOfParts = 4; - partSize = range/noOfParts; - } - - // Special case: 0 - if(range === 0) { - noOfParts = 5; - partSize = 1; - } - - let intervals = []; - for(var i = 0; i <= noOfParts; i++){ - intervals.push(lowerBound + partSize * i); - } - return intervals; -} - -function getChartIntervals(maxValue, minValue=0) { - let [normalMaxValue, exponent] = normalize(maxValue); - let normalMinValue = minValue ? minValue/Math.pow(10, exponent): 0; - - // Allow only 7 significant digits - normalMaxValue = normalMaxValue.toFixed(6); - - let intervals = getChartRangeIntervals(normalMaxValue, normalMinValue); - intervals = intervals.map(value => value * Math.pow(10, exponent)); - return intervals; -} - -export function calcChartIntervals(values, withMinimum=false) { - //*** Where the magic happens *** - - // Calculates best-fit y intervals from given values - // and returns the interval array - - let maxValue = Math.max(...values); - let minValue = Math.min(...values); - - // Exponent to be used for pretty print - let exponent = 0, intervals = []; // eslint-disable-line no-unused-vars - - function getPositiveFirstIntervals(maxValue, absMinValue) { - let intervals = getChartIntervals(maxValue); - - let intervalSize = intervals[1] - intervals[0]; - - // Then unshift the negative values - let value = 0; - for(var i = 1; value < absMinValue; i++) { - value += intervalSize; - intervals.unshift((-1) * value); - } - return intervals; - } - - // CASE I: Both non-negative - - if(maxValue >= 0 && minValue >= 0) { - exponent = normalize(maxValue)[1]; - if(!withMinimum) { - intervals = getChartIntervals(maxValue); - } else { - intervals = getChartIntervals(maxValue, minValue); - } - } - - // CASE II: Only minValue negative - - else if(maxValue > 0 && minValue < 0) { - // `withMinimum` irrelevant in this case, - // We'll be handling both sides of zero separately - // (both starting from zero) - // Because ceil() and floor() behave differently - // in those two regions - - let absMinValue = Math.abs(minValue); - - if(maxValue >= absMinValue) { - exponent = normalize(maxValue)[1]; - intervals = getPositiveFirstIntervals(maxValue, absMinValue); - } else { - // Mirror: maxValue => absMinValue, then change sign - exponent = normalize(absMinValue)[1]; - let posIntervals = getPositiveFirstIntervals(absMinValue, maxValue); - intervals = posIntervals.reverse().map(d => d * (-1)); - } - - } - - // CASE III: Both non-positive - - else if(maxValue <= 0 && minValue <= 0) { - // Mirrored Case I: - // Work with positives, then reverse the sign and array - - let pseudoMaxValue = Math.abs(minValue); - let pseudoMinValue = Math.abs(maxValue); - - exponent = normalize(pseudoMaxValue)[1]; - if(!withMinimum) { - intervals = getChartIntervals(pseudoMaxValue); - } else { - intervals = getChartIntervals(pseudoMaxValue, pseudoMinValue); - } - - intervals = intervals.reverse().map(d => d * (-1)); - } - - return intervals; -} - -export function getZeroIndex(yPts) { - let zeroIndex; - let interval = getIntervalSize(yPts); - if(yPts.indexOf(0) >= 0) { - // the range has a given zero - // zero-line on the chart - zeroIndex = yPts.indexOf(0); - } else if(yPts[0] > 0) { - // Minimum value is positive - // zero-line is off the chart: below - let min = yPts[0]; - zeroIndex = (-1) * min / interval; - } else { - // Maximum value is negative - // zero-line is off the chart: above - let max = yPts[yPts.length - 1]; - zeroIndex = (-1) * max / interval + (yPts.length - 1); - } - return zeroIndex; -} - -export function getRealIntervals(max, noOfIntervals, min = 0, asc = 1) { - let range = max - min; - let part = range * 1.0 / noOfIntervals; - let intervals = []; - - for(var i = 0; i <= noOfIntervals; i++) { - intervals.push(min + part * i); - } - - return asc ? intervals : intervals.reverse(); -} - -export function getIntervalSize(orderedArray) { - return orderedArray[1] - orderedArray[0]; -} - -export function getValueRange(orderedArray) { - return orderedArray[orderedArray.length-1] - orderedArray[0]; -} - -export function scale(val, yAxis) { - return floatTwo(yAxis.zeroLine - val * yAxis.scaleMultiplier); -} - -export function isInRange(val, min, max) { - return val > min && val < max; -} - -export function isInRange2D(coord, minCoord, maxCoord) { - return isInRange(coord[0], minCoord[0], maxCoord[0]) - && isInRange(coord[1], minCoord[1], maxCoord[1]); -} - -export function getClosestInArray(goal, arr, index = false) { - let closest = arr.reduce(function(prev, curr) { - return (Math.abs(curr - goal) < Math.abs(prev - goal) ? curr : prev); - }, []); - - return index ? arr.indexOf(closest) : closest; -} - -export function calcDistribution(values, distributionSize) { - // Assume non-negative values, - // implying distribution minimum at zero - - let dataMaxValue = Math.max(...values); - - let distributionStep = 1 / (distributionSize - 1); - let distribution = []; - - for(var i = 0; i < distributionSize; i++) { - let checkpoint = dataMaxValue * (distributionStep * i); - distribution.push(checkpoint); - } - - return distribution; -} - -export function getMaxCheckpoint(value, distribution) { - return distribution.filter(d => d < value).length; -} diff --git a/node_modules/frappe-charts/src/js/utils/test/colors.test.js b/node_modules/frappe-charts/src/js/utils/test/colors.test.js deleted file mode 100644 index 3b8d276..0000000 --- a/node_modules/frappe-charts/src/js/utils/test/colors.test.js +++ /dev/null @@ -1,14 +0,0 @@ -const assert = require('assert'); -const colors = require('../colors'); - -describe('utils.colors', () => { - it('should return #aaabac for RGB()', () => { - assert.equal(colors.getColor('rgb(170, 171, 172)'), '#aaabac'); - }); - it('should return #ff5858 for the named color red', () => { - assert.equal(colors.getColor('red'), '#ff5858d'); - }); - it('should return #1a5c29 for the hex color #1a5c29', () => { - assert.equal(colors.getColor('#1a5c29'), '#1a5c29'); - }); -}); \ No newline at end of file diff --git a/node_modules/frappe-charts/src/js/utils/test/helpers.test.js b/node_modules/frappe-charts/src/js/utils/test/helpers.test.js deleted file mode 100644 index 0d8e7e3..0000000 --- a/node_modules/frappe-charts/src/js/utils/test/helpers.test.js +++ /dev/null @@ -1,10 +0,0 @@ -const assert = require('assert'); -const helpers = require('../helpers'); - -describe('utils.helpers', () => { - it('should return a value fixed upto 2 decimals', () => { - assert.equal(helpers.floatTwo(1.234), 1.23); - assert.equal(helpers.floatTwo(1.456), 1.46); - assert.equal(helpers.floatTwo(1), 1.00); - }); -}); \ No newline at end of file diff --git a/node_modules/function-bind/.editorconfig b/node_modules/function-bind/.editorconfig deleted file mode 100644 index ac29ade..0000000 --- a/node_modules/function-bind/.editorconfig +++ /dev/null @@ -1,20 +0,0 @@ -root = true - -[*] -indent_style = tab -indent_size = 4 -end_of_line = lf -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true -max_line_length = 120 - -[CHANGELOG.md] -indent_style = space -indent_size = 2 - -[*.json] -max_line_length = off - -[Makefile] -max_line_length = off diff --git a/node_modules/function-bind/.eslintrc b/node_modules/function-bind/.eslintrc deleted file mode 100644 index 9b33d8e..0000000 --- a/node_modules/function-bind/.eslintrc +++ /dev/null @@ -1,15 +0,0 @@ -{ - "root": true, - - "extends": "@ljharb", - - "rules": { - "func-name-matching": 0, - "indent": [2, 4], - "max-nested-callbacks": [2, 3], - "max-params": [2, 3], - "max-statements": [2, 20], - "no-new-func": [1], - "strict": [0] - } -} diff --git a/node_modules/function-bind/.jscs.json b/node_modules/function-bind/.jscs.json deleted file mode 100644 index 8c44794..0000000 --- a/node_modules/function-bind/.jscs.json +++ /dev/null @@ -1,176 +0,0 @@ -{ - "es3": true, - - "additionalRules": [], - - "requireSemicolons": true, - - "disallowMultipleSpaces": true, - - "disallowIdentifierNames": [], - - "requireCurlyBraces": { - "allExcept": [], - "keywords": ["if", "else", "for", "while", "do", "try", "catch"] - }, - - "requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch", "function"], - - "disallowSpaceAfterKeywords": [], - - "disallowSpaceBeforeComma": true, - "disallowSpaceAfterComma": false, - "disallowSpaceBeforeSemicolon": true, - - "disallowNodeTypes": [ - "DebuggerStatement", - "ForInStatement", - "LabeledStatement", - "SwitchCase", - "SwitchStatement", - "WithStatement" - ], - - "requireObjectKeysOnNewLine": { "allExcept": ["sameLine"] }, - - "requireSpacesInAnonymousFunctionExpression": { "beforeOpeningRoundBrace": true, "beforeOpeningCurlyBrace": true }, - "requireSpacesInNamedFunctionExpression": { "beforeOpeningCurlyBrace": true }, - "disallowSpacesInNamedFunctionExpression": { "beforeOpeningRoundBrace": true }, - "requireSpacesInFunctionDeclaration": { "beforeOpeningCurlyBrace": true }, - "disallowSpacesInFunctionDeclaration": { "beforeOpeningRoundBrace": true }, - - "requireSpaceBetweenArguments": true, - - "disallowSpacesInsideParentheses": true, - - "disallowSpacesInsideArrayBrackets": true, - - "disallowQuotedKeysInObjects": { "allExcept": ["reserved"] }, - - "disallowSpaceAfterObjectKeys": true, - - "requireCommaBeforeLineBreak": true, - - "disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"], - "requireSpaceAfterPrefixUnaryOperators": [], - - "disallowSpaceBeforePostfixUnaryOperators": ["++", "--"], - "requireSpaceBeforePostfixUnaryOperators": [], - - "disallowSpaceBeforeBinaryOperators": [], - "requireSpaceBeforeBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="], - - "requireSpaceAfterBinaryOperators": ["+", "-", "/", "*", "=", "==", "===", "!=", "!=="], - "disallowSpaceAfterBinaryOperators": [], - - "disallowImplicitTypeConversion": ["binary", "string"], - - "disallowKeywords": ["with", "eval"], - - "requireKeywordsOnNewLine": [], - "disallowKeywordsOnNewLine": ["else"], - - "requireLineFeedAtFileEnd": true, - - "disallowTrailingWhitespace": true, - - "disallowTrailingComma": true, - - "excludeFiles": ["node_modules/**", "vendor/**"], - - "disallowMultipleLineStrings": true, - - "requireDotNotation": { "allExcept": ["keywords"] }, - - "requireParenthesesAroundIIFE": true, - - "validateLineBreaks": "LF", - - "validateQuoteMarks": { - "escape": true, - "mark": "'" - }, - - "disallowOperatorBeforeLineBreak": [], - - "requireSpaceBeforeKeywords": [ - "do", - "for", - "if", - "else", - "switch", - "case", - "try", - "catch", - "finally", - "while", - "with", - "return" - ], - - "validateAlignedFunctionParameters": { - "lineBreakAfterOpeningBraces": true, - "lineBreakBeforeClosingBraces": true - }, - - "requirePaddingNewLinesBeforeExport": true, - - "validateNewlineAfterArrayElements": { - "maximum": 8 - }, - - "requirePaddingNewLinesAfterUseStrict": true, - - "disallowArrowFunctions": true, - - "disallowMultiLineTernary": true, - - "validateOrderInObjectKeys": "asc-insensitive", - - "disallowIdenticalDestructuringNames": true, - - "disallowNestedTernaries": { "maxLevel": 1 }, - - "requireSpaceAfterComma": { "allExcept": ["trailing"] }, - "requireAlignedMultilineParams": false, - - "requireSpacesInGenerator": { - "afterStar": true - }, - - "disallowSpacesInGenerator": { - "beforeStar": true - }, - - "disallowVar": false, - - "requireArrayDestructuring": false, - - "requireEnhancedObjectLiterals": false, - - "requireObjectDestructuring": false, - - "requireEarlyReturn": false, - - "requireCapitalizedConstructorsNew": { - "allExcept": ["Function", "String", "Object", "Symbol", "Number", "Date", "RegExp", "Error", "Boolean", "Array"] - }, - - "requireImportAlphabetized": false, - - "requireSpaceBeforeObjectValues": true, - "requireSpaceBeforeDestructuredValues": true, - - "disallowSpacesInsideTemplateStringPlaceholders": true, - - "disallowArrayDestructuringReturn": false, - - "requireNewlineBeforeSingleStatementsInIf": false, - - "disallowUnusedVariables": true, - - "requireSpacesInsideImportedObjectBraces": true, - - "requireUseStrict": true -} - diff --git a/node_modules/function-bind/.npmignore b/node_modules/function-bind/.npmignore deleted file mode 100644 index dbb555f..0000000 --- a/node_modules/function-bind/.npmignore +++ /dev/null @@ -1,22 +0,0 @@ -# gitignore -.DS_Store -.monitor -.*.swp -.nodemonignore -releases -*.log -*.err -fleet.json -public/browserify -bin/*.json -.bin -build -compile -.lock-wscript -coverage -node_modules - -# Only apps should have lockfiles -npm-shrinkwrap.json -package-lock.json -yarn.lock diff --git a/node_modules/function-bind/.travis.yml b/node_modules/function-bind/.travis.yml deleted file mode 100644 index 85f70d2..0000000 --- a/node_modules/function-bind/.travis.yml +++ /dev/null @@ -1,168 +0,0 @@ -language: node_js -os: - - linux -node_js: - - "8.4" - - "7.10" - - "6.11" - - "5.12" - - "4.8" - - "iojs-v3.3" - - "iojs-v2.5" - - "iojs-v1.8" - - "0.12" - - "0.10" - - "0.8" -before_install: - - 'if [ "${TRAVIS_NODE_VERSION}" = "0.6" ]; then npm install -g npm@1.3 ; elif [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then case "$(npm --version)" in 1.*) npm install -g npm@1.4.28 ;; 2.*) npm install -g npm@2 ;; esac ; fi' - - 'if [ "${TRAVIS_NODE_VERSION}" != "0.6" ] && [ "${TRAVIS_NODE_VERSION}" != "0.9" ]; then if [ "${TRAVIS_NODE_VERSION%${TRAVIS_NODE_VERSION#[0-9]}}" = "0" ] || [ "${TRAVIS_NODE_VERSION:0:4}" = "iojs" ]; then npm install -g npm@4.5 ; else npm install -g npm; fi; fi' -install: - - 'if [ "${TRAVIS_NODE_VERSION}" = "0.6" ]; then nvm install 0.8 && npm install -g npm@1.3 && npm install -g npm@1.4.28 && npm install -g npm@2 && npm install && nvm use "${TRAVIS_NODE_VERSION}"; else npm install; fi;' -script: - - 'if [ -n "${PRETEST-}" ]; then npm run pretest ; fi' - - 'if [ -n "${POSTTEST-}" ]; then npm run posttest ; fi' - - 'if [ -n "${COVERAGE-}" ]; then npm run coverage ; fi' - - 'if [ -n "${TEST-}" ]; then npm run tests-only ; fi' -sudo: false -env: - - TEST=true -matrix: - fast_finish: true - include: - - node_js: "node" - env: PRETEST=true - - node_js: "4" - env: COVERAGE=true - - node_js: "8.3" - env: TEST=true ALLOW_FAILURE=true - - node_js: "8.2" - env: TEST=true ALLOW_FAILURE=true - - node_js: "8.1" - env: TEST=true ALLOW_FAILURE=true - - node_js: "8.0" - env: TEST=true ALLOW_FAILURE=true - - node_js: "7.9" - env: TEST=true ALLOW_FAILURE=true - - node_js: "7.8" - env: TEST=true ALLOW_FAILURE=true - - node_js: "7.7" - env: TEST=true ALLOW_FAILURE=true - - node_js: "7.6" - env: TEST=true ALLOW_FAILURE=true - - node_js: "7.5" - env: TEST=true ALLOW_FAILURE=true - - node_js: "7.4" - env: TEST=true ALLOW_FAILURE=true - - node_js: "7.3" - env: TEST=true ALLOW_FAILURE=true - - node_js: "7.2" - env: TEST=true ALLOW_FAILURE=true - - node_js: "7.1" - env: TEST=true ALLOW_FAILURE=true - - node_js: "7.0" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.10" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.9" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.8" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.7" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.6" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.5" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.4" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.3" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.2" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.1" - env: TEST=true ALLOW_FAILURE=true - - node_js: "6.0" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.11" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.10" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.9" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.8" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.7" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.6" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.5" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.4" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.3" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.2" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.1" - env: TEST=true ALLOW_FAILURE=true - - node_js: "5.0" - env: TEST=true ALLOW_FAILURE=true - - node_js: "4.7" - env: TEST=true ALLOW_FAILURE=true - - node_js: "4.6" - env: TEST=true ALLOW_FAILURE=true - - node_js: "4.5" - env: TEST=true ALLOW_FAILURE=true - - node_js: "4.4" - env: TEST=true ALLOW_FAILURE=true - - node_js: "4.3" - env: TEST=true ALLOW_FAILURE=true - - node_js: "4.2" - env: TEST=true ALLOW_FAILURE=true - - node_js: "4.1" - env: TEST=true ALLOW_FAILURE=true - - node_js: "4.0" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v3.2" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v3.1" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v3.0" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v2.4" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v2.3" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v2.2" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v2.1" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v2.0" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v1.7" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v1.6" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v1.5" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v1.4" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v1.3" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v1.2" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v1.1" - env: TEST=true ALLOW_FAILURE=true - - node_js: "iojs-v1.0" - env: TEST=true ALLOW_FAILURE=true - - node_js: "0.11" - env: TEST=true ALLOW_FAILURE=true - - node_js: "0.9" - env: TEST=true ALLOW_FAILURE=true - - node_js: "0.6" - env: TEST=true ALLOW_FAILURE=true - - node_js: "0.4" - env: TEST=true ALLOW_FAILURE=true - allow_failures: - - os: osx - - env: TEST=true ALLOW_FAILURE=true diff --git a/node_modules/function-bind/LICENSE b/node_modules/function-bind/LICENSE deleted file mode 100644 index 62d6d23..0000000 --- a/node_modules/function-bind/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2013 Raynos. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - diff --git a/node_modules/function-bind/README.md b/node_modules/function-bind/README.md deleted file mode 100644 index 81862a0..0000000 --- a/node_modules/function-bind/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# function-bind - - - - - -Implementation of function.prototype.bind - -## Example - -I mainly do this for unit tests I run on phantomjs. -PhantomJS does not have Function.prototype.bind :( - -```js -Function.prototype.bind = require("function-bind") -``` - -## Installation - -`npm install function-bind` - -## Contributors - - - Raynos - -## MIT Licenced - - [travis-svg]: https://travis-ci.org/Raynos/function-bind.svg - [travis-url]: https://travis-ci.org/Raynos/function-bind - [npm-badge-svg]: https://badge.fury.io/js/function-bind.svg - [npm-url]: https://npmjs.org/package/function-bind - [5]: https://coveralls.io/repos/Raynos/function-bind/badge.png - [6]: https://coveralls.io/r/Raynos/function-bind - [7]: https://gemnasium.com/Raynos/function-bind.png - [8]: https://gemnasium.com/Raynos/function-bind - [deps-svg]: https://david-dm.org/Raynos/function-bind.svg - [deps-url]: https://david-dm.org/Raynos/function-bind - [dev-deps-svg]: https://david-dm.org/Raynos/function-bind/dev-status.svg - [dev-deps-url]: https://david-dm.org/Raynos/function-bind#info=devDependencies - [11]: https://ci.testling.com/Raynos/function-bind.png - [12]: https://ci.testling.com/Raynos/function-bind diff --git a/node_modules/function-bind/implementation.js b/node_modules/function-bind/implementation.js deleted file mode 100644 index cc4daec..0000000 --- a/node_modules/function-bind/implementation.js +++ /dev/null @@ -1,52 +0,0 @@ -'use strict'; - -/* eslint no-invalid-this: 1 */ - -var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; -var slice = Array.prototype.slice; -var toStr = Object.prototype.toString; -var funcType = '[object Function]'; - -module.exports = function bind(that) { - var target = this; - if (typeof target !== 'function' || toStr.call(target) !== funcType) { - throw new TypeError(ERROR_MESSAGE + target); - } - var args = slice.call(arguments, 1); - - var bound; - var binder = function () { - if (this instanceof bound) { - var result = target.apply( - this, - args.concat(slice.call(arguments)) - ); - if (Object(result) === result) { - return result; - } - return this; - } else { - return target.apply( - that, - args.concat(slice.call(arguments)) - ); - } - }; - - var boundLength = Math.max(0, target.length - args.length); - var boundArgs = []; - for (var i = 0; i < boundLength; i++) { - boundArgs.push('$' + i); - } - - bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); - - if (target.prototype) { - var Empty = function Empty() {}; - Empty.prototype = target.prototype; - bound.prototype = new Empty(); - Empty.prototype = null; - } - - return bound; -}; diff --git a/node_modules/function-bind/index.js b/node_modules/function-bind/index.js deleted file mode 100644 index 3bb6b96..0000000 --- a/node_modules/function-bind/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -var implementation = require('./implementation'); - -module.exports = Function.prototype.bind || implementation; diff --git a/node_modules/function-bind/package.json b/node_modules/function-bind/package.json deleted file mode 100644 index 20a1727..0000000 --- a/node_modules/function-bind/package.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "name": "function-bind", - "version": "1.1.1", - "description": "Implementation of Function.prototype.bind", - "keywords": [ - "function", - "bind", - "shim", - "es5" - ], - "author": "Raynos ", - "repository": "git://github.com/Raynos/function-bind.git", - "main": "index", - "homepage": "https://github.com/Raynos/function-bind", - "contributors": [ - { - "name": "Raynos" - }, - { - "name": "Jordan Harband", - "url": "https://github.com/ljharb" - } - ], - "bugs": { - "url": "https://github.com/Raynos/function-bind/issues", - "email": "raynos2@gmail.com" - }, - "dependencies": {}, - "devDependencies": { - "@ljharb/eslint-config": "^12.2.1", - "covert": "^1.1.0", - "eslint": "^4.5.0", - "jscs": "^3.0.7", - "tape": "^4.8.0" - }, - "license": "MIT", - "scripts": { - "pretest": "npm run lint", - "test": "npm run tests-only", - "posttest": "npm run coverage -- --quiet", - "tests-only": "node test", - "coverage": "covert test/*.js", - "lint": "npm run jscs && npm run eslint", - "jscs": "jscs *.js */*.js", - "eslint": "eslint *.js */*.js" - }, - "testling": { - "files": "test/index.js", - "browsers": [ - "ie/8..latest", - "firefox/16..latest", - "firefox/nightly", - "chrome/22..latest", - "chrome/canary", - "opera/12..latest", - "opera/next", - "safari/5.1..latest", - "ipad/6.0..latest", - "iphone/6.0..latest", - "android-browser/4.2..latest" - ] - } -} diff --git a/node_modules/function-bind/test/.eslintrc b/node_modules/function-bind/test/.eslintrc deleted file mode 100644 index 8a56d5b..0000000 --- a/node_modules/function-bind/test/.eslintrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "rules": { - "array-bracket-newline": 0, - "array-element-newline": 0, - "max-statements-per-line": [2, { "max": 2 }], - "no-invalid-this": 0, - "no-magic-numbers": 0, - } -} diff --git a/node_modules/function-bind/test/index.js b/node_modules/function-bind/test/index.js deleted file mode 100644 index 2edecce..0000000 --- a/node_modules/function-bind/test/index.js +++ /dev/null @@ -1,252 +0,0 @@ -// jscs:disable requireUseStrict - -var test = require('tape'); - -var functionBind = require('../implementation'); -var getCurrentContext = function () { return this; }; - -test('functionBind is a function', function (t) { - t.equal(typeof functionBind, 'function'); - t.end(); -}); - -test('non-functions', function (t) { - var nonFunctions = [true, false, [], {}, 42, 'foo', NaN, /a/g]; - t.plan(nonFunctions.length); - for (var i = 0; i < nonFunctions.length; ++i) { - try { functionBind.call(nonFunctions[i]); } catch (ex) { - t.ok(ex instanceof TypeError, 'throws when given ' + String(nonFunctions[i])); - } - } - t.end(); -}); - -test('without a context', function (t) { - t.test('binds properly', function (st) { - var args, context; - var namespace = { - func: functionBind.call(function () { - args = Array.prototype.slice.call(arguments); - context = this; - }) - }; - namespace.func(1, 2, 3); - st.deepEqual(args, [1, 2, 3]); - st.equal(context, getCurrentContext.call()); - st.end(); - }); - - t.test('binds properly, and still supplies bound arguments', function (st) { - var args, context; - var namespace = { - func: functionBind.call(function () { - args = Array.prototype.slice.call(arguments); - context = this; - }, undefined, 1, 2, 3) - }; - namespace.func(4, 5, 6); - st.deepEqual(args, [1, 2, 3, 4, 5, 6]); - st.equal(context, getCurrentContext.call()); - st.end(); - }); - - t.test('returns properly', function (st) { - var args; - var namespace = { - func: functionBind.call(function () { - args = Array.prototype.slice.call(arguments); - return this; - }, null) - }; - var context = namespace.func(1, 2, 3); - st.equal(context, getCurrentContext.call(), 'returned context is namespaced context'); - st.deepEqual(args, [1, 2, 3], 'passed arguments are correct'); - st.end(); - }); - - t.test('returns properly with bound arguments', function (st) { - var args; - var namespace = { - func: functionBind.call(function () { - args = Array.prototype.slice.call(arguments); - return this; - }, null, 1, 2, 3) - }; - var context = namespace.func(4, 5, 6); - st.equal(context, getCurrentContext.call(), 'returned context is namespaced context'); - st.deepEqual(args, [1, 2, 3, 4, 5, 6], 'passed arguments are correct'); - st.end(); - }); - - t.test('called as a constructor', function (st) { - var thunkify = function (value) { - return function () { return value; }; - }; - st.test('returns object value', function (sst) { - var expectedReturnValue = [1, 2, 3]; - var Constructor = functionBind.call(thunkify(expectedReturnValue), null); - var result = new Constructor(); - sst.equal(result, expectedReturnValue); - sst.end(); - }); - - st.test('does not return primitive value', function (sst) { - var Constructor = functionBind.call(thunkify(42), null); - var result = new Constructor(); - sst.notEqual(result, 42); - sst.end(); - }); - - st.test('object from bound constructor is instance of original and bound constructor', function (sst) { - var A = function (x) { - this.name = x || 'A'; - }; - var B = functionBind.call(A, null, 'B'); - - var result = new B(); - sst.ok(result instanceof B, 'result is instance of bound constructor'); - sst.ok(result instanceof A, 'result is instance of original constructor'); - sst.end(); - }); - - st.end(); - }); - - t.end(); -}); - -test('with a context', function (t) { - t.test('with no bound arguments', function (st) { - var args, context; - var boundContext = {}; - var namespace = { - func: functionBind.call(function () { - args = Array.prototype.slice.call(arguments); - context = this; - }, boundContext) - }; - namespace.func(1, 2, 3); - st.equal(context, boundContext, 'binds a context properly'); - st.deepEqual(args, [1, 2, 3], 'supplies passed arguments'); - st.end(); - }); - - t.test('with bound arguments', function (st) { - var args, context; - var boundContext = {}; - var namespace = { - func: functionBind.call(function () { - args = Array.prototype.slice.call(arguments); - context = this; - }, boundContext, 1, 2, 3) - }; - namespace.func(4, 5, 6); - st.equal(context, boundContext, 'binds a context properly'); - st.deepEqual(args, [1, 2, 3, 4, 5, 6], 'supplies bound and passed arguments'); - st.end(); - }); - - t.test('returns properly', function (st) { - var boundContext = {}; - var args; - var namespace = { - func: functionBind.call(function () { - args = Array.prototype.slice.call(arguments); - return this; - }, boundContext) - }; - var context = namespace.func(1, 2, 3); - st.equal(context, boundContext, 'returned context is bound context'); - st.notEqual(context, getCurrentContext.call(), 'returned context is not lexical context'); - st.deepEqual(args, [1, 2, 3], 'passed arguments are correct'); - st.end(); - }); - - t.test('returns properly with bound arguments', function (st) { - var boundContext = {}; - var args; - var namespace = { - func: functionBind.call(function () { - args = Array.prototype.slice.call(arguments); - return this; - }, boundContext, 1, 2, 3) - }; - var context = namespace.func(4, 5, 6); - st.equal(context, boundContext, 'returned context is bound context'); - st.notEqual(context, getCurrentContext.call(), 'returned context is not lexical context'); - st.deepEqual(args, [1, 2, 3, 4, 5, 6], 'passed arguments are correct'); - st.end(); - }); - - t.test('passes the correct arguments when called as a constructor', function (st) { - var expected = { name: 'Correct' }; - var namespace = { - Func: functionBind.call(function (arg) { - return arg; - }, { name: 'Incorrect' }) - }; - var returned = new namespace.Func(expected); - st.equal(returned, expected, 'returns the right arg when called as a constructor'); - st.end(); - }); - - t.test('has the new instance\'s context when called as a constructor', function (st) { - var actualContext; - var expectedContext = { foo: 'bar' }; - var namespace = { - Func: functionBind.call(function () { - actualContext = this; - }, expectedContext) - }; - var result = new namespace.Func(); - st.equal(result instanceof namespace.Func, true); - st.notEqual(actualContext, expectedContext); - st.end(); - }); - - t.end(); -}); - -test('bound function length', function (t) { - t.test('sets a correct length without thisArg', function (st) { - var subject = functionBind.call(function (a, b, c) { return a + b + c; }); - st.equal(subject.length, 3); - st.equal(subject(1, 2, 3), 6); - st.end(); - }); - - t.test('sets a correct length with thisArg', function (st) { - var subject = functionBind.call(function (a, b, c) { return a + b + c; }, {}); - st.equal(subject.length, 3); - st.equal(subject(1, 2, 3), 6); - st.end(); - }); - - t.test('sets a correct length without thisArg and first argument', function (st) { - var subject = functionBind.call(function (a, b, c) { return a + b + c; }, undefined, 1); - st.equal(subject.length, 2); - st.equal(subject(2, 3), 6); - st.end(); - }); - - t.test('sets a correct length with thisArg and first argument', function (st) { - var subject = functionBind.call(function (a, b, c) { return a + b + c; }, {}, 1); - st.equal(subject.length, 2); - st.equal(subject(2, 3), 6); - st.end(); - }); - - t.test('sets a correct length without thisArg and too many arguments', function (st) { - var subject = functionBind.call(function (a, b, c) { return a + b + c; }, undefined, 1, 2, 3, 4); - st.equal(subject.length, 0); - st.equal(subject(), 6); - st.end(); - }); - - t.test('sets a correct length with thisArg and too many arguments', function (st) { - var subject = functionBind.call(function (a, b, c) { return a + b + c; }, {}, 1, 2, 3, 4); - st.equal(subject.length, 0); - st.equal(subject(), 6); - st.end(); - }); -}); diff --git a/node_modules/has/LICENSE-MIT b/node_modules/has/LICENSE-MIT deleted file mode 100644 index ae7014d..0000000 --- a/node_modules/has/LICENSE-MIT +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2013 Thiago de Arruda - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/has/README.md b/node_modules/has/README.md deleted file mode 100644 index 635e3a4..0000000 --- a/node_modules/has/README.md +++ /dev/null @@ -1,18 +0,0 @@ -# has - -> Object.prototype.hasOwnProperty.call shortcut - -## Installation - -```sh -npm install --save has -``` - -## Usage - -```js -var has = require('has'); - -has({}, 'hasOwnProperty'); // false -has(Object.prototype, 'hasOwnProperty'); // true -``` diff --git a/node_modules/has/package.json b/node_modules/has/package.json deleted file mode 100644 index 7c4592f..0000000 --- a/node_modules/has/package.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "name": "has", - "description": "Object.prototype.hasOwnProperty.call shortcut", - "version": "1.0.3", - "homepage": "https://github.com/tarruda/has", - "author": { - "name": "Thiago de Arruda", - "email": "tpadilha84@gmail.com" - }, - "contributors": [ - { - "name": "Jordan Harband", - "email": "ljharb@gmail.com", - "url": "http://ljharb.codes" - } - ], - "repository": { - "type": "git", - "url": "git://github.com/tarruda/has.git" - }, - "bugs": { - "url": "https://github.com/tarruda/has/issues" - }, - "license": "MIT", - "licenses": [ - { - "type": "MIT", - "url": "https://github.com/tarruda/has/blob/master/LICENSE-MIT" - } - ], - "main": "./src", - "dependencies": { - "function-bind": "^1.1.1" - }, - "devDependencies": { - "@ljharb/eslint-config": "^12.2.1", - "eslint": "^4.19.1", - "tape": "^4.9.0" - }, - "engines": { - "node": ">= 0.4.0" - }, - "scripts": { - "lint": "eslint .", - "pretest": "npm run lint", - "test": "tape test" - } -} diff --git a/node_modules/has/src/index.js b/node_modules/has/src/index.js deleted file mode 100644 index dd92dd9..0000000 --- a/node_modules/has/src/index.js +++ /dev/null @@ -1,5 +0,0 @@ -'use strict'; - -var bind = require('function-bind'); - -module.exports = bind.call(Function.call, Object.prototype.hasOwnProperty); diff --git a/node_modules/has/test/index.js b/node_modules/has/test/index.js deleted file mode 100644 index 43d480b..0000000 --- a/node_modules/has/test/index.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; - -var test = require('tape'); -var has = require('../'); - -test('has', function (t) { - t.equal(has({}, 'hasOwnProperty'), false, 'object literal does not have own property "hasOwnProperty"'); - t.equal(has(Object.prototype, 'hasOwnProperty'), true, 'Object.prototype has own property "hasOwnProperty"'); - t.end(); -}); diff --git a/node_modules/is-core-module/.eslintignore b/node_modules/is-core-module/.eslintignore deleted file mode 100644 index 404abb2..0000000 --- a/node_modules/is-core-module/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -coverage/ diff --git a/node_modules/is-core-module/.eslintrc b/node_modules/is-core-module/.eslintrc deleted file mode 100644 index 9c7d516..0000000 --- a/node_modules/is-core-module/.eslintrc +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "@ljharb", - "root": true, - "rules": { - "func-style": 1, - "operator-linebreak": [2, "before"], - }, - "overrides": [ - { - "files": "test/**", - "rules": { - "global-require": 0, - "max-lines-per-function": 0, - "no-negated-condition": 0, - }, - }, - ], -} diff --git a/node_modules/is-core-module/.nycrc b/node_modules/is-core-module/.nycrc deleted file mode 100644 index bdd626c..0000000 --- a/node_modules/is-core-module/.nycrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "all": true, - "check-coverage": false, - "reporter": ["text-summary", "text", "html", "json"], - "exclude": [ - "coverage", - "test" - ] -} diff --git a/node_modules/is-core-module/CHANGELOG.md b/node_modules/is-core-module/CHANGELOG.md deleted file mode 100644 index c88cf3d..0000000 --- a/node_modules/is-core-module/CHANGELOG.md +++ /dev/null @@ -1,117 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [v2.8.0](https://github.com/inspect-js/is-core-module/compare/v2.7.0...v2.8.0) - 2021-10-14 - -### Commits - -- [actions] update codecov uploader [`0cfe94e`](https://github.com/inspect-js/is-core-module/commit/0cfe94e106a7d005ea03e008c0a21dec13a77904) -- [New] add `readline/promises` to node v17+ [`4f78c30`](https://github.com/inspect-js/is-core-module/commit/4f78c3008b1b58b4db6dc91d99610b1bc859da7e) -- [Tests] node ^14.18 supports `node:` prefixes for CJS [`43e2f17`](https://github.com/inspect-js/is-core-module/commit/43e2f177452cea2f0eaf34f61b5407217bbdb6f4) - -## [v2.7.0](https://github.com/inspect-js/is-core-module/compare/v2.6.0...v2.7.0) - 2021-09-27 - -### Commits - -- [New] node `v14.18` added `node:`-prefixed core modules to `require` [`6d943ab`](https://github.com/inspect-js/is-core-module/commit/6d943abe81382b9bbe344384d80fbfebe1cc0526) -- [Tests] add coverage for Object.prototype pollution [`c6baf5f`](https://github.com/inspect-js/is-core-module/commit/c6baf5f942311a1945c1af41167bb80b84df2af7) -- [Dev Deps] update `@ljharb/eslint-config` [`6717f00`](https://github.com/inspect-js/is-core-module/commit/6717f000d063ea57beb772bded36c2f056ac404c) -- [eslint] fix linter warning [`594c10b`](https://github.com/inspect-js/is-core-module/commit/594c10bb7d39d7eb00925c90924199ff596184b2) -- [meta] add `sideEffects` flag [`c32cfa5`](https://github.com/inspect-js/is-core-module/commit/c32cfa5195632944c4dd4284a142b8476e75be13) - -## [v2.6.0](https://github.com/inspect-js/is-core-module/compare/v2.5.0...v2.6.0) - 2021-08-17 - -### Commits - -- [Dev Deps] update `eslint`, `tape` [`6cc928f`](https://github.com/inspect-js/is-core-module/commit/6cc928f8a4bba66aeeccc4f6beeac736d4bd3081) -- [New] add `stream/consumers` to node `>= 16.7` [`a1a423e`](https://github.com/inspect-js/is-core-module/commit/a1a423e467e4cc27df180234fad5bab45943e67d) -- [Refactor] Remove duplicated `&&` operand [`86faea7`](https://github.com/inspect-js/is-core-module/commit/86faea738213a2433c62d1098488dc9314dca832) -- [Tests] include prereleases [`a4da7a6`](https://github.com/inspect-js/is-core-module/commit/a4da7a6abf7568e2aa4fd98e69452179f1850963) - -## [v2.5.0](https://github.com/inspect-js/is-core-module/compare/v2.4.0...v2.5.0) - 2021-07-12 - -### Commits - -- [Dev Deps] update `auto-changelog`, `eslint` [`6334cc9`](https://github.com/inspect-js/is-core-module/commit/6334cc94f3af7469685bd8f236740991baaf2705) -- [New] add `stream/web` to node v16.5+ [`17ac59b`](https://github.com/inspect-js/is-core-module/commit/17ac59b662d63e220a2e5728625f005c24f177b2) - -## [v2.4.0](https://github.com/inspect-js/is-core-module/compare/v2.3.0...v2.4.0) - 2021-05-09 - -### Commits - -- [readme] add actions and codecov badges [`82b7faa`](https://github.com/inspect-js/is-core-module/commit/82b7faa12b56dbe47fbea67e1a5b9e447027ba40) -- [Dev Deps] update `@ljharb/eslint-config`, `aud` [`8096868`](https://github.com/inspect-js/is-core-module/commit/8096868c024a161ccd4d44110b136763e92eace8) -- [Dev Deps] update `eslint` [`6726824`](https://github.com/inspect-js/is-core-module/commit/67268249b88230018c510f6532a8046d7326346f) -- [New] add `diagnostics_channel` to node `^14.17` [`86c6563`](https://github.com/inspect-js/is-core-module/commit/86c65634201b8ff9b3e48a9a782594579c7f5c3c) -- [meta] fix prepublish script [`697a01e`](https://github.com/inspect-js/is-core-module/commit/697a01e3c9c0be074066520954f30fb28532ec57) - -## [v2.3.0](https://github.com/inspect-js/is-core-module/compare/v2.2.0...v2.3.0) - 2021-04-24 - -### Commits - -- [meta] do not publish github action workflow files [`060d4bb`](https://github.com/inspect-js/is-core-module/commit/060d4bb971a29451c19ff336eb56bee27f9fa95a) -- [New] add support for `node:` prefix, in node 16+ [`7341223`](https://github.com/inspect-js/is-core-module/commit/73412230a769f6e81c05eea50b6520cebf54ed2f) -- [actions] use `node/install` instead of `node/run`; use `codecov` action [`016269a`](https://github.com/inspect-js/is-core-module/commit/016269abae9f6657a5254adfbb813f09a05067f9) -- [patch] remove unneeded `.0` in version ranges [`cb466a6`](https://github.com/inspect-js/is-core-module/commit/cb466a6d89e52b8389e5c12715efcd550c41cea3) -- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `aud`, `tape` [`c9f9c39`](https://github.com/inspect-js/is-core-module/commit/c9f9c396ace60ef81906f98059c064e6452473ed) -- [actions] update workflows [`3ee4a89`](https://github.com/inspect-js/is-core-module/commit/3ee4a89fd5a02fccd43882d905448ea6a98e9a3c) -- [Dev Deps] update `eslint`, `@ljharb/eslint-config` [`dee4fed`](https://github.com/inspect-js/is-core-module/commit/dee4fed79690c1d43a22f7fa9426abebdc6d727f) -- [Dev Deps] update `eslint`, `@ljharb/eslint-config` [`7d046ba`](https://github.com/inspect-js/is-core-module/commit/7d046ba07ae8c9292e43652694ca808d7b309de8) -- [meta] use `prepublishOnly` script for npm 7+ [`149e677`](https://github.com/inspect-js/is-core-module/commit/149e6771a5ede6d097e71785b467a9c4b4977cc7) -- [readme] remove travis badge [`903b51d`](https://github.com/inspect-js/is-core-module/commit/903b51d6b69b98abeabfbc3695c345b02646f19c) - -## [v2.2.0](https://github.com/inspect-js/is-core-module/compare/v2.1.0...v2.2.0) - 2020-11-26 - -### Commits - -- [Tests] migrate tests to Github Actions [`c919f57`](https://github.com/inspect-js/is-core-module/commit/c919f573c0a92d10a0acad0b650b5aecb033d426) -- [patch] `core.json`: %s/ /\t/g [`db3f685`](https://github.com/inspect-js/is-core-module/commit/db3f68581f53e73cc09cd675955eb1bdd6a5a39b) -- [Tests] run `nyc` on all tests [`b2f925f`](https://github.com/inspect-js/is-core-module/commit/b2f925f8866f210ef441f39fcc8cc42692ab89b1) -- [Dev Deps] update `eslint`, `@ljharb/eslint-config`, `aud`; add `safe-publish-latest` [`89f02a2`](https://github.com/inspect-js/is-core-module/commit/89f02a2b4162246dea303a6ee31bb9a550b05c72) -- [New] add `path/posix`, `path/win32`, `util/types` [`77f94f1`](https://github.com/inspect-js/is-core-module/commit/77f94f1e90ffd7c0be2a3f1aa8574ebf7fd981b3) - -## [v2.1.0](https://github.com/inspect-js/is-core-module/compare/v2.0.0...v2.1.0) - 2020-11-04 - -### Commits - -- [Dev Deps] update `eslint` [`5e0034e`](https://github.com/inspect-js/is-core-module/commit/5e0034eae57c09c8f1bd769f502486a00f56c6e4) -- [New] Add `diagnostics_channel` [`c2d83d0`](https://github.com/inspect-js/is-core-module/commit/c2d83d0a0225a1a658945d9bab7036ea347d29ec) - -## [v2.0.0](https://github.com/inspect-js/is-core-module/compare/v1.0.2...v2.0.0) - 2020-09-29 - -### Commits - -- v2 implementation [`865aeb5`](https://github.com/inspect-js/is-core-module/commit/865aeb5ca0e90248a3dfff5d7622e4751fdeb9cd) -- Only apps should have lockfiles [`5a5e660`](https://github.com/inspect-js/is-core-module/commit/5a5e660d568e37eb44e17fb1ebb12a105205fc2b) -- Initial commit for v2 [`5a51524`](https://github.com/inspect-js/is-core-module/commit/5a51524e06f92adece5fbb138c69b7b9748a2348) -- Tests [`116eae4`](https://github.com/inspect-js/is-core-module/commit/116eae4fccd01bc72c1fd3cc4b7561c387afc496) -- [meta] add `auto-changelog` [`c24388b`](https://github.com/inspect-js/is-core-module/commit/c24388bee828d223040519d1f5b226ca35beee63) -- [actions] add "Automatic Rebase" and "require allow edits" actions [`34292db`](https://github.com/inspect-js/is-core-module/commit/34292dbcbadae0868aff03c22dbd8b7b8a11558a) -- [Tests] add `npm run lint` [`4f9eeee`](https://github.com/inspect-js/is-core-module/commit/4f9eeee7ddff10698bbf528620f4dc8d4fa3e697) -- [readme] fix travis badges, https all URLs [`e516a73`](https://github.com/inspect-js/is-core-module/commit/e516a73b0dccce20938c432b1ba512eae8eff9e9) -- [meta] create FUNDING.yml [`1aabebc`](https://github.com/inspect-js/is-core-module/commit/1aabebca98d01f8a04e46bc2e2520fa93cf21ac6) -- [Fix] `domain`: domain landed sometime > v0.7.7 and <= v0.7.12 [`2df7d37`](https://github.com/inspect-js/is-core-module/commit/2df7d37595d41b15eeada732b706b926c2771655) -- [Fix] `sys`: worked in 0.6, not 0.7, and 0.8+ [`a75c134`](https://github.com/inspect-js/is-core-module/commit/a75c134229e1e9441801f6b73f6a52489346eb65) - -## [v1.0.2](https://github.com/inspect-js/is-core-module/compare/v1.0.1...v1.0.2) - 2014-09-28 - -### Commits - -- simpler [`66fe90f`](https://github.com/inspect-js/is-core-module/commit/66fe90f9771581b9adc0c3900baa52c21b5baea2) - -## [v1.0.1](https://github.com/inspect-js/is-core-module/compare/v1.0.0...v1.0.1) - 2014-09-28 - -### Commits - -- remove stupid [`f21f906`](https://github.com/inspect-js/is-core-module/commit/f21f906f882c2bd656a5fc5ed6fbe48ddaffb2ac) -- update readme [`1eff0ec`](https://github.com/inspect-js/is-core-module/commit/1eff0ec69798d1ec65771552d1562911e90a8027) - -## v1.0.0 - 2014-09-28 - -### Commits - -- init [`48e5e76`](https://github.com/inspect-js/is-core-module/commit/48e5e76cac378fddb8c1f7d4055b8dfc943d6b96) diff --git a/node_modules/is-core-module/LICENSE b/node_modules/is-core-module/LICENSE deleted file mode 100644 index 2e50287..0000000 --- a/node_modules/is-core-module/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Dave Justice - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/node_modules/is-core-module/README.md b/node_modules/is-core-module/README.md deleted file mode 100644 index 062d906..0000000 --- a/node_modules/is-core-module/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# is-core-module [![Version Badge][2]][1] - -[![github actions][actions-image]][actions-url] -[![coverage][codecov-image]][codecov-url] -[![dependency status][5]][6] -[![dev dependency status][7]][8] -[![License][license-image]][license-url] -[![Downloads][downloads-image]][downloads-url] - -[![npm badge][11]][1] - -Is this specifier a node.js core module? Optionally provide a node version to check; defaults to the current node version. - -## Example - -```js -var isCore = require('is-core-module'); -var assert = require('assert'); -assert(isCore('fs')); -assert(!isCore('butts')); -``` - -## Tests -Clone the repo, `npm install`, and run `npm test` - -[1]: https://npmjs.org/package/is-core-module -[2]: https://versionbadg.es/inspect-js/is-core-module.svg -[5]: https://david-dm.org/inspect-js/is-core-module.svg -[6]: https://david-dm.org/inspect-js/is-core-module -[7]: https://david-dm.org/inspect-js/is-core-module/dev-status.svg -[8]: https://david-dm.org/inspect-js/is-core-module#info=devDependencies -[11]: https://nodei.co/npm/is-core-module.png?downloads=true&stars=true -[license-image]: https://img.shields.io/npm/l/is-core-module.svg -[license-url]: LICENSE -[downloads-image]: https://img.shields.io/npm/dm/is-core-module.svg -[downloads-url]: https://npm-stat.com/charts.html?package=is-core-module -[codecov-image]: https://codecov.io/gh/inspect-js/is-core-module/branch/main/graphs/badge.svg -[codecov-url]: https://app.codecov.io/gh/inspect-js/is-core-module/ -[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/inspect-js/is-core-module -[actions-url]: https://github.com/inspect-js/is-core-module/actions diff --git a/node_modules/is-core-module/core.json b/node_modules/is-core-module/core.json deleted file mode 100644 index 8f4ad12..0000000 --- a/node_modules/is-core-module/core.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "assert": true, - "node:assert": [">= 14.18 && < 15", ">= 16"], - "assert/strict": ">= 15", - "node:assert/strict": ">= 16", - "async_hooks": ">= 8", - "node:async_hooks": [">= 14.18 && < 15", ">= 16"], - "buffer_ieee754": "< 0.9.7", - "buffer": true, - "node:buffer": [">= 14.18 && < 15", ">= 16"], - "child_process": true, - "node:child_process": [">= 14.18 && < 15", ">= 16"], - "cluster": true, - "node:cluster": [">= 14.18 && < 15", ">= 16"], - "console": true, - "node:console": [">= 14.18 && < 15", ">= 16"], - "constants": true, - "node:constants": [">= 14.18 && < 15", ">= 16"], - "crypto": true, - "node:crypto": [">= 14.18 && < 15", ">= 16"], - "_debug_agent": ">= 1 && < 8", - "_debugger": "< 8", - "dgram": true, - "node:dgram": [">= 14.18 && < 15", ">= 16"], - "diagnostics_channel": [">= 14.17 && < 15", ">= 15.1"], - "node:diagnostics_channel": [">= 14.18 && < 15", ">= 16"], - "dns": true, - "node:dns": [">= 14.18 && < 15", ">= 16"], - "dns/promises": ">= 15", - "node:dns/promises": ">= 16", - "domain": ">= 0.7.12", - "node:domain": [">= 14.18 && < 15", ">= 16"], - "events": true, - "node:events": [">= 14.18 && < 15", ">= 16"], - "freelist": "< 6", - "fs": true, - "node:fs": [">= 14.18 && < 15", ">= 16"], - "fs/promises": [">= 10 && < 10.1", ">= 14"], - "node:fs/promises": [">= 14.18 && < 15", ">= 16"], - "_http_agent": ">= 0.11.1", - "node:_http_agent": [">= 14.18 && < 15", ">= 16"], - "_http_client": ">= 0.11.1", - "node:_http_client": [">= 14.18 && < 15", ">= 16"], - "_http_common": ">= 0.11.1", - "node:_http_common": [">= 14.18 && < 15", ">= 16"], - "_http_incoming": ">= 0.11.1", - "node:_http_incoming": [">= 14.18 && < 15", ">= 16"], - "_http_outgoing": ">= 0.11.1", - "node:_http_outgoing": [">= 14.18 && < 15", ">= 16"], - "_http_server": ">= 0.11.1", - "node:_http_server": [">= 14.18 && < 15", ">= 16"], - "http": true, - "node:http": [">= 14.18 && < 15", ">= 16"], - "http2": ">= 8.8", - "node:http2": [">= 14.18 && < 15", ">= 16"], - "https": true, - "node:https": [">= 14.18 && < 15", ">= 16"], - "inspector": ">= 8", - "node:inspector": [">= 14.18 && < 15", ">= 16"], - "_linklist": "< 8", - "module": true, - "node:module": [">= 14.18 && < 15", ">= 16"], - "net": true, - "node:net": [">= 14.18 && < 15", ">= 16"], - "node-inspect/lib/_inspect": ">= 7.6 && < 12", - "node-inspect/lib/internal/inspect_client": ">= 7.6 && < 12", - "node-inspect/lib/internal/inspect_repl": ">= 7.6 && < 12", - "os": true, - "node:os": [">= 14.18 && < 15", ">= 16"], - "path": true, - "node:path": [">= 14.18 && < 15", ">= 16"], - "path/posix": ">= 15.3", - "node:path/posix": ">= 16", - "path/win32": ">= 15.3", - "node:path/win32": ">= 16", - "perf_hooks": ">= 8.5", - "node:perf_hooks": [">= 14.18 && < 15", ">= 16"], - "process": ">= 1", - "node:process": [">= 14.18 && < 15", ">= 16"], - "punycode": true, - "node:punycode": [">= 14.18 && < 15", ">= 16"], - "querystring": true, - "node:querystring": [">= 14.18 && < 15", ">= 16"], - "readline": true, - "node:readline": [">= 14.18 && < 15", ">= 16"], - "readline/promises": ">= 17", - "node:readline/promises": ">= 17", - "repl": true, - "node:repl": [">= 14.18 && < 15", ">= 16"], - "smalloc": ">= 0.11.5 && < 3", - "_stream_duplex": ">= 0.9.4", - "node:_stream_duplex": [">= 14.18 && < 15", ">= 16"], - "_stream_transform": ">= 0.9.4", - "node:_stream_transform": [">= 14.18 && < 15", ">= 16"], - "_stream_wrap": ">= 1.4.1", - "node:_stream_wrap": [">= 14.18 && < 15", ">= 16"], - "_stream_passthrough": ">= 0.9.4", - "node:_stream_passthrough": [">= 14.18 && < 15", ">= 16"], - "_stream_readable": ">= 0.9.4", - "node:_stream_readable": [">= 14.18 && < 15", ">= 16"], - "_stream_writable": ">= 0.9.4", - "node:_stream_writable": [">= 14.18 && < 15", ">= 16"], - "stream": true, - "node:stream": [">= 14.18 && < 15", ">= 16"], - "stream/consumers": ">= 16.7", - "node:stream/consumers": ">= 16.7", - "stream/promises": ">= 15", - "node:stream/promises": ">= 16", - "stream/web": ">= 16.5", - "node:stream/web": ">= 16.5", - "string_decoder": true, - "node:string_decoder": [">= 14.18 && < 15", ">= 16"], - "sys": [">= 0.6 && < 0.7", ">= 0.8"], - "node:sys": [">= 14.18 && < 15", ">= 16"], - "timers": true, - "node:timers": [">= 14.18 && < 15", ">= 16"], - "timers/promises": ">= 15", - "node:timers/promises": ">= 16", - "_tls_common": ">= 0.11.13", - "node:_tls_common": [">= 14.18 && < 15", ">= 16"], - "_tls_legacy": ">= 0.11.3 && < 10", - "_tls_wrap": ">= 0.11.3", - "node:_tls_wrap": [">= 14.18 && < 15", ">= 16"], - "tls": true, - "node:tls": [">= 14.18 && < 15", ">= 16"], - "trace_events": ">= 10", - "node:trace_events": [">= 14.18 && < 15", ">= 16"], - "tty": true, - "node:tty": [">= 14.18 && < 15", ">= 16"], - "url": true, - "node:url": [">= 14.18 && < 15", ">= 16"], - "util": true, - "node:util": [">= 14.18 && < 15", ">= 16"], - "util/types": ">= 15.3", - "node:util/types": ">= 16", - "v8/tools/arguments": ">= 10 && < 12", - "v8/tools/codemap": [">= 4.4 && < 5", ">= 5.2 && < 12"], - "v8/tools/consarray": [">= 4.4 && < 5", ">= 5.2 && < 12"], - "v8/tools/csvparser": [">= 4.4 && < 5", ">= 5.2 && < 12"], - "v8/tools/logreader": [">= 4.4 && < 5", ">= 5.2 && < 12"], - "v8/tools/profile_view": [">= 4.4 && < 5", ">= 5.2 && < 12"], - "v8/tools/splaytree": [">= 4.4 && < 5", ">= 5.2 && < 12"], - "v8": ">= 1", - "node:v8": [">= 14.18 && < 15", ">= 16"], - "vm": true, - "node:vm": [">= 14.18 && < 15", ">= 16"], - "wasi": ">= 13.4 && < 13.5", - "worker_threads": ">= 11.7", - "node:worker_threads": [">= 14.18 && < 15", ">= 16"], - "zlib": true, - "node:zlib": [">= 14.18 && < 15", ">= 16"] -} diff --git a/node_modules/is-core-module/index.js b/node_modules/is-core-module/index.js deleted file mode 100644 index f9637e0..0000000 --- a/node_modules/is-core-module/index.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -var has = require('has'); - -function specifierIncluded(current, specifier) { - var nodeParts = current.split('.'); - var parts = specifier.split(' '); - var op = parts.length > 1 ? parts[0] : '='; - var versionParts = (parts.length > 1 ? parts[1] : parts[0]).split('.'); - - for (var i = 0; i < 3; ++i) { - var cur = parseInt(nodeParts[i] || 0, 10); - var ver = parseInt(versionParts[i] || 0, 10); - if (cur === ver) { - continue; // eslint-disable-line no-restricted-syntax, no-continue - } - if (op === '<') { - return cur < ver; - } - if (op === '>=') { - return cur >= ver; - } - return false; - } - return op === '>='; -} - -function matchesRange(current, range) { - var specifiers = range.split(/ ?&& ?/); - if (specifiers.length === 0) { - return false; - } - for (var i = 0; i < specifiers.length; ++i) { - if (!specifierIncluded(current, specifiers[i])) { - return false; - } - } - return true; -} - -function versionIncluded(nodeVersion, specifierValue) { - if (typeof specifierValue === 'boolean') { - return specifierValue; - } - - var current = typeof nodeVersion === 'undefined' - ? process.versions && process.versions.node - : nodeVersion; - - if (typeof current !== 'string') { - throw new TypeError(typeof nodeVersion === 'undefined' ? 'Unable to determine current node version' : 'If provided, a valid node version is required'); - } - - if (specifierValue && typeof specifierValue === 'object') { - for (var i = 0; i < specifierValue.length; ++i) { - if (matchesRange(current, specifierValue[i])) { - return true; - } - } - return false; - } - return matchesRange(current, specifierValue); -} - -var data = require('./core.json'); - -module.exports = function isCore(x, nodeVersion) { - return has(data, x) && versionIncluded(nodeVersion, data[x]); -}; diff --git a/node_modules/is-core-module/package.json b/node_modules/is-core-module/package.json deleted file mode 100644 index 7847059..0000000 --- a/node_modules/is-core-module/package.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "name": "is-core-module", - "version": "2.8.0", - "description": "Is this specifier a node.js core module?", - "main": "index.js", - "sideEffects": false, - "exports": { - ".": [ - { - "default": "./index.js" - }, - "./index.js" - ], - "./package.json": "./package.json" - }, - "scripts": { - "prepublish": "not-in-publish || npm run prepublishOnly", - "prepublishOnly": "safe-publish-latest", - "lint": "eslint .", - "pretest": "npm run lint", - "tests-only": "tape 'test/**/*.js'", - "test": "nyc npm run tests-only", - "posttest": "aud --production", - "version": "auto-changelog && git add CHANGELOG.md", - "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/inspect-js/is-core-module.git" - }, - "keywords": [ - "core", - "modules", - "module", - "npm", - "node", - "dependencies" - ], - "author": "Jordan Harband ", - "funding": { - "url": "https://github.com/sponsors/ljharb" - }, - "license": "MIT", - "bugs": { - "url": "https://github.com/inspect-js/is-core-module/issues" - }, - "homepage": "https://github.com/inspect-js/is-core-module", - "dependencies": { - "has": "^1.0.3" - }, - "devDependencies": { - "@ljharb/eslint-config": "^18.0.0", - "aud": "^1.1.5", - "auto-changelog": "^2.3.0", - "eslint": "^7.32.0", - "nyc": "^10.3.2", - "safe-publish-latest": "^1.1.4", - "semver": "^6.3.0", - "tape": "^5.3.1" - }, - "auto-changelog": { - "output": "CHANGELOG.md", - "template": "keepachangelog", - "unreleased": false, - "commitLimit": false, - "backfillLimit": false, - "hideCredit": true - } -} diff --git a/node_modules/is-core-module/test/index.js b/node_modules/is-core-module/test/index.js deleted file mode 100644 index b688cd2..0000000 --- a/node_modules/is-core-module/test/index.js +++ /dev/null @@ -1,130 +0,0 @@ -'use strict'; - -var test = require('tape'); -var keys = require('object-keys'); -var semver = require('semver'); -var isCore = require('../'); -var data = require('../core.json'); - -var supportsNodePrefix = semver.satisfies(process.versions.node, '^14.18 || >= 16', { includePrerelease: true }); - -test('core modules', function (t) { - t.test('isCore()', function (st) { - st.ok(isCore('fs')); - st.ok(isCore('net')); - st.ok(isCore('http')); - - st.ok(!isCore('seq')); - st.ok(!isCore('../')); - - st.ok(!isCore('toString')); - - st.end(); - }); - - t.test('core list', function (st) { - var cores = keys(data); - st.plan(cores.length); - - for (var i = 0; i < cores.length; ++i) { - var mod = cores[i]; - var requireFunc = function () { require(mod); }; // eslint-disable-line no-loop-func - if (isCore(mod)) { - st.doesNotThrow(requireFunc, mod + ' supported; requiring does not throw'); - } else { - st['throws'](requireFunc, mod + ' not supported; requiring throws'); - } - } - - st.end(); - }); - - t.test('core via repl module', { skip: !data.repl }, function (st) { - var libs = require('repl')._builtinLibs; // eslint-disable-line no-underscore-dangle - if (!libs) { - st.skip('module.builtinModules does not exist'); - } else { - for (var i = 0; i < libs.length; ++i) { - var mod = libs[i]; - st.ok(data[mod], mod + ' is a core module'); - st.doesNotThrow( - function () { require(mod); }, // eslint-disable-line no-loop-func - 'requiring ' + mod + ' does not throw' - ); - if (supportsNodePrefix) { - st.doesNotThrow( - function () { require('node:' + mod); }, // eslint-disable-line no-loop-func - 'requiring node:' + mod + ' does not throw' - ); - } else { - st['throws']( - function () { require('node:' + mod); }, // eslint-disable-line no-loop-func - 'requiring node:' + mod + ' throws' - ); - } - } - } - st.end(); - }); - - t.test('core via builtinModules list', { skip: !data.module }, function (st) { - var libs = require('module').builtinModules; - if (!libs) { - st.skip('module.builtinModules does not exist'); - } else { - var excludeList = [ - '_debug_agent', - 'v8/tools/tickprocessor-driver', - 'v8/tools/SourceMap', - 'v8/tools/tickprocessor', - 'v8/tools/profile' - ]; - for (var i = 0; i < libs.length; ++i) { - var mod = libs[i]; - if (excludeList.indexOf(mod) === -1) { - st.ok(data[mod], mod + ' is a core module'); - st.doesNotThrow( - function () { require(mod); }, // eslint-disable-line no-loop-func - 'requiring ' + mod + ' does not throw' - ); - if (supportsNodePrefix) { - st.doesNotThrow( - function () { require('node:' + mod); }, // eslint-disable-line no-loop-func - 'requiring node:' + mod + ' does not throw' - ); - } else { - st['throws']( - function () { require('node:' + mod); }, // eslint-disable-line no-loop-func - 'requiring node:' + mod + ' throws' - ); - } - } - } - } - st.end(); - }); - - t.test('Object.prototype pollution', function (st) { - /* eslint no-extend-native: 1 */ - var nonKey = 'not a core module'; - st.teardown(function () { - delete Object.prototype.fs; - delete Object.prototype.path; - delete Object.prototype.http; - delete Object.prototype[nonKey]; - }); - Object.prototype.fs = false; - Object.prototype.path = '>= 999999999'; - Object.prototype.http = data.http; - Object.prototype[nonKey] = true; - - st.equal(isCore('fs'), true, 'fs is a core module even if Object.prototype lies'); - st.equal(isCore('path'), true, 'path is a core module even if Object.prototype lies'); - st.equal(isCore('http'), true, 'path is a core module even if Object.prototype matches data'); - st.equal(isCore(nonKey), false, '"' + nonKey + '" is not a core module even if Object.prototype lies'); - - st.end(); - }); - - t.end(); -}); diff --git a/node_modules/nanoid/LICENSE b/node_modules/nanoid/LICENSE deleted file mode 100644 index 37f56aa..0000000 --- a/node_modules/nanoid/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright 2017 Andrey Sitnik - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/node_modules/nanoid/README.md b/node_modules/nanoid/README.md deleted file mode 100644 index f666d33..0000000 --- a/node_modules/nanoid/README.md +++ /dev/null @@ -1,39 +0,0 @@ -# Nano ID - -Nano ID logo by Anton Lovchikov - -**English** | [Русский](./README.ru.md) | [简体中文](./README.zh-CN.md) - -A tiny, secure, URL-friendly, unique string ID generator for JavaScript. - -> “An amazing level of senseless perfectionism, -> which is simply impossible not to respect.” - -* **Small.** 130 bytes (minified and gzipped). No dependencies. - [Size Limit] controls the size. -* **Fast.** It is 2 times faster than UUID. -* **Safe.** It uses hardware random generator. Can be used in clusters. -* **Short IDs.** It uses a larger alphabet than UUID (`A-Za-z0-9_-`). - So ID size was reduced from 36 to 21 symbols. -* **Portable.** Nano ID was ported - to [19 programming languages](#other-programming-languages). - -```js -import { nanoid } from 'nanoid' -model.id = nanoid() //=> "V1StGXR8_Z5jdHi6B-myT" -``` - -Supports modern browsers, IE [with Babel], Node.js and React Native. - -[online tool]: https://gitpod.io/#https://github.com/ai/nanoid/ -[with Babel]: https://developer.epages.com/blog/coding/how-to-transpile-node-modules-with-babel-and-webpack-in-a-monorepo/ -[Size Limit]: https://github.com/ai/size-limit - -
                  - Sponsored by Evil Martians - - -## Docs -Read **[full docs](https://github.com/ai/nanoid#readme)** on GitHub. diff --git a/node_modules/nanoid/async/index.browser.cjs b/node_modules/nanoid/async/index.browser.cjs deleted file mode 100644 index aeacf81..0000000 --- a/node_modules/nanoid/async/index.browser.cjs +++ /dev/null @@ -1,35 +0,0 @@ -let random = bytes => - Promise.resolve(crypto.getRandomValues(new Uint8Array(bytes))) -let customAlphabet = (alphabet, size) => { - let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1 - let step = -~((1.6 * mask * size) / alphabet.length) - return () => { - let id = '' - while (true) { - let bytes = crypto.getRandomValues(new Uint8Array(step)) - let i = step - while (i--) { - id += alphabet[bytes[i] & mask] || '' - if (id.length === size) return Promise.resolve(id) - } - } - } -} -let nanoid = (size = 21) => { - let id = '' - let bytes = crypto.getRandomValues(new Uint8Array(size)) - while (size--) { - let byte = bytes[size] & 63 - if (byte < 36) { - id += byte.toString(36) - } else if (byte < 62) { - id += (byte - 26).toString(36).toUpperCase() - } else if (byte < 63) { - id += '_' - } else { - id += '-' - } - } - return Promise.resolve(id) -} -module.exports = { nanoid, customAlphabet, random } diff --git a/node_modules/nanoid/async/index.browser.js b/node_modules/nanoid/async/index.browser.js deleted file mode 100644 index fcbaf68..0000000 --- a/node_modules/nanoid/async/index.browser.js +++ /dev/null @@ -1,35 +0,0 @@ -let random = bytes => - Promise.resolve(crypto.getRandomValues(new Uint8Array(bytes))) -let customAlphabet = (alphabet, size) => { - let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1 - let step = -~((1.6 * mask * size) / alphabet.length) - return () => { - let id = '' - while (true) { - let bytes = crypto.getRandomValues(new Uint8Array(step)) - let i = step - while (i--) { - id += alphabet[bytes[i] & mask] || '' - if (id.length === size) return Promise.resolve(id) - } - } - } -} -let nanoid = (size = 21) => { - let id = '' - let bytes = crypto.getRandomValues(new Uint8Array(size)) - while (size--) { - let byte = bytes[size] & 63 - if (byte < 36) { - id += byte.toString(36) - } else if (byte < 62) { - id += (byte - 26).toString(36).toUpperCase() - } else if (byte < 63) { - id += '_' - } else { - id += '-' - } - } - return Promise.resolve(id) -} -export { nanoid, customAlphabet, random } diff --git a/node_modules/nanoid/async/index.cjs b/node_modules/nanoid/async/index.cjs deleted file mode 100644 index 397ec28..0000000 --- a/node_modules/nanoid/async/index.cjs +++ /dev/null @@ -1,35 +0,0 @@ -let crypto = require('crypto') -let { urlAlphabet } = require('../url-alphabet/index.cjs') -let random = bytes => - new Promise((resolve, reject) => { - crypto.randomFill(Buffer.allocUnsafe(bytes), (err, buf) => { - if (err) { - reject(err) - } else { - resolve(buf) - } - }) - }) -let customAlphabet = (alphabet, size) => { - let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1 - let step = Math.ceil((1.6 * mask * size) / alphabet.length) - let tick = id => - random(step).then(bytes => { - let i = step - while (i--) { - id += alphabet[bytes[i] & mask] || '' - if (id.length === size) return id - } - return tick(id) - }) - return () => tick('') -} -let nanoid = (size = 21) => - random(size).then(bytes => { - let id = '' - while (size--) { - id += urlAlphabet[bytes[size] & 63] - } - return id - }) -module.exports = { nanoid, customAlphabet, random } diff --git a/node_modules/nanoid/async/index.d.ts b/node_modules/nanoid/async/index.d.ts deleted file mode 100644 index 3933d25..0000000 --- a/node_modules/nanoid/async/index.d.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Generate secure URL-friendly unique ID. The non-blocking version. - * - * By default, the ID will have 21 symbols to have a collision probability - * similar to UUID v4. - * - * ```js - * import { nanoid } from 'nanoid/async' - * nanoid().then(id => { - * model.id = id - * }) - * ``` - * - * @param size Size of the ID. The default size is 21. - * @returns A promise with a random string. - */ -export function nanoid(size?: number): Promise - -/** - * A low-level function. - * Generate secure unique ID with custom alphabet. The non-blocking version. - * - * Alphabet must contain 256 symbols or less. Otherwise, the generator - * will not be secure. - * - * @param alphabet Alphabet used to generate the ID. - * @param size Size of the ID. - * @returns A promise with a random string. - * - * ```js - * import { customAlphabet } from 'nanoid/async' - * const nanoid = customAlphabet('0123456789абвгдеё', 5) - * nanoid().then(id => { - * model.id = id //=> "8ё56а" - * }) - * ``` - */ -export function customAlphabet( - alphabet: string, - size: number -): () => Promise - -/** - * Generate an array of random bytes collected from hardware noise. - * - * ```js - * import { random } from 'nanoid/async' - * random(5).then(bytes => { - * bytes //=> [10, 67, 212, 67, 89] - * }) - * ``` - * - * @param bytes Size of the array. - * @returns A promise with a random bytes array. - */ -export function random(bytes: number): Promise diff --git a/node_modules/nanoid/async/index.js b/node_modules/nanoid/async/index.js deleted file mode 100644 index cf2763d..0000000 --- a/node_modules/nanoid/async/index.js +++ /dev/null @@ -1,35 +0,0 @@ -import crypto from 'crypto' -import { urlAlphabet } from '../url-alphabet/index.js' -let random = bytes => - new Promise((resolve, reject) => { - crypto.randomFill(Buffer.allocUnsafe(bytes), (err, buf) => { - if (err) { - reject(err) - } else { - resolve(buf) - } - }) - }) -let customAlphabet = (alphabet, size) => { - let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1 - let step = Math.ceil((1.6 * mask * size) / alphabet.length) - let tick = id => - random(step).then(bytes => { - let i = step - while (i--) { - id += alphabet[bytes[i] & mask] || '' - if (id.length === size) return id - } - return tick(id) - }) - return () => tick('') -} -let nanoid = (size = 21) => - random(size).then(bytes => { - let id = '' - while (size--) { - id += urlAlphabet[bytes[size] & 63] - } - return id - }) -export { nanoid, customAlphabet, random } diff --git a/node_modules/nanoid/async/index.native.js b/node_modules/nanoid/async/index.native.js deleted file mode 100644 index 95a4cba..0000000 --- a/node_modules/nanoid/async/index.native.js +++ /dev/null @@ -1,26 +0,0 @@ -import { getRandomBytesAsync } from 'expo-random' -import { urlAlphabet } from '../url-alphabet/index.js' -let random = getRandomBytesAsync -let customAlphabet = (alphabet, size) => { - let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1 - let step = Math.ceil((1.6 * mask * size) / alphabet.length) - let tick = id => - random(step).then(bytes => { - let i = step - while (i--) { - id += alphabet[bytes[i] & mask] || '' - if (id.length === size) return id - } - return tick(id) - }) - return () => tick('') -} -let nanoid = (size = 21) => - random(size).then(bytes => { - let id = '' - while (size--) { - id += urlAlphabet[bytes[size] & 63] - } - return id - }) -export { nanoid, customAlphabet, random } diff --git a/node_modules/nanoid/async/package.json b/node_modules/nanoid/async/package.json deleted file mode 100644 index 578cdb4..0000000 --- a/node_modules/nanoid/async/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "type": "module", - "main": "index.cjs", - "module": "index.js", - "react-native": { - "./index.js": "./index.native.js" - }, - "browser": { - "./index.js": "./index.browser.js", - "./index.cjs": "./index.browser.cjs" - } -} \ No newline at end of file diff --git a/node_modules/nanoid/bin/nanoid.cjs b/node_modules/nanoid/bin/nanoid.cjs deleted file mode 100755 index e14116f..0000000 --- a/node_modules/nanoid/bin/nanoid.cjs +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env node - -let { nanoid } = require('..') - -process.stdout.write(nanoid() + '\n') diff --git a/node_modules/nanoid/index.browser.cjs b/node_modules/nanoid/index.browser.cjs deleted file mode 100644 index 74f0a8c..0000000 --- a/node_modules/nanoid/index.browser.cjs +++ /dev/null @@ -1,62 +0,0 @@ -let { urlAlphabet } = require('./url-alphabet/index.cjs') -if (process.env.NODE_ENV !== 'production') { - if ( - typeof navigator !== 'undefined' && - navigator.product === 'ReactNative' && - typeof crypto === 'undefined' - ) { - throw new Error( - 'React Native does not have a built-in secure random generator. ' + - 'If you don’t need unpredictable IDs use `nanoid/non-secure`. ' + - 'For secure IDs, import `react-native-get-random-values` ' + - 'before Nano ID.' - ) - } - if (typeof msCrypto !== 'undefined' && typeof crypto === 'undefined') { - throw new Error( - 'Import file with `if (!window.crypto) window.crypto = window.msCrypto`' + - ' before importing Nano ID to fix IE 11 support' - ) - } - if (typeof crypto === 'undefined') { - throw new Error( - 'Your browser does not have secure random generator. ' + - 'If you don’t need unpredictable IDs, you can use nanoid/non-secure.' - ) - } -} -let random = bytes => crypto.getRandomValues(new Uint8Array(bytes)) -let customRandom = (alphabet, size, getRandom) => { - let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1 - let step = -~((1.6 * mask * size) / alphabet.length) - return () => { - let id = '' - while (true) { - let bytes = getRandom(step) - let j = step - while (j--) { - id += alphabet[bytes[j] & mask] || '' - if (id.length === size) return id - } - } - } -} -let customAlphabet = (alphabet, size) => customRandom(alphabet, size, random) -let nanoid = (size = 21) => { - let id = '' - let bytes = crypto.getRandomValues(new Uint8Array(size)) - while (size--) { - let byte = bytes[size] & 63 - if (byte < 36) { - id += byte.toString(36) - } else if (byte < 62) { - id += (byte - 26).toString(36).toUpperCase() - } else if (byte < 63) { - id += '_' - } else { - id += '-' - } - } - return id -} -module.exports = { nanoid, customAlphabet, customRandom, urlAlphabet, random } diff --git a/node_modules/nanoid/index.browser.js b/node_modules/nanoid/index.browser.js deleted file mode 100644 index 3e32e59..0000000 --- a/node_modules/nanoid/index.browser.js +++ /dev/null @@ -1,62 +0,0 @@ -import { urlAlphabet } from './url-alphabet/index.js' -if (process.env.NODE_ENV !== 'production') { - if ( - typeof navigator !== 'undefined' && - navigator.product === 'ReactNative' && - typeof crypto === 'undefined' - ) { - throw new Error( - 'React Native does not have a built-in secure random generator. ' + - 'If you don’t need unpredictable IDs use `nanoid/non-secure`. ' + - 'For secure IDs, import `react-native-get-random-values` ' + - 'before Nano ID.' - ) - } - if (typeof msCrypto !== 'undefined' && typeof crypto === 'undefined') { - throw new Error( - 'Import file with `if (!window.crypto) window.crypto = window.msCrypto`' + - ' before importing Nano ID to fix IE 11 support' - ) - } - if (typeof crypto === 'undefined') { - throw new Error( - 'Your browser does not have secure random generator. ' + - 'If you don’t need unpredictable IDs, you can use nanoid/non-secure.' - ) - } -} -let random = bytes => crypto.getRandomValues(new Uint8Array(bytes)) -let customRandom = (alphabet, size, getRandom) => { - let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1 - let step = -~((1.6 * mask * size) / alphabet.length) - return () => { - let id = '' - while (true) { - let bytes = getRandom(step) - let j = step - while (j--) { - id += alphabet[bytes[j] & mask] || '' - if (id.length === size) return id - } - } - } -} -let customAlphabet = (alphabet, size) => customRandom(alphabet, size, random) -let nanoid = (size = 21) => { - let id = '' - let bytes = crypto.getRandomValues(new Uint8Array(size)) - while (size--) { - let byte = bytes[size] & 63 - if (byte < 36) { - id += byte.toString(36) - } else if (byte < 62) { - id += (byte - 26).toString(36).toUpperCase() - } else if (byte < 63) { - id += '_' - } else { - id += '-' - } - } - return id -} -export { nanoid, customAlphabet, customRandom, urlAlphabet, random } diff --git a/node_modules/nanoid/index.cjs b/node_modules/nanoid/index.cjs deleted file mode 100644 index 3e6eb39..0000000 --- a/node_modules/nanoid/index.cjs +++ /dev/null @@ -1,44 +0,0 @@ -let crypto = require('crypto') -let { urlAlphabet } = require('./url-alphabet/index.cjs') -const POOL_SIZE_MULTIPLIER = 128 -let pool, poolOffset -let fillPool = bytes => { - if (!pool || pool.length < bytes) { - pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER) - crypto.randomFillSync(pool) - poolOffset = 0 - } else if (poolOffset + bytes > pool.length) { - crypto.randomFillSync(pool) - poolOffset = 0 - } - poolOffset += bytes -} -let random = bytes => { - fillPool(bytes) - return pool.subarray(poolOffset - bytes, poolOffset) -} -let customRandom = (alphabet, size, getRandom) => { - let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1 - let step = Math.ceil((1.6 * mask * size) / alphabet.length) - return () => { - let id = '' - while (true) { - let bytes = getRandom(step) - let i = step - while (i--) { - id += alphabet[bytes[i] & mask] || '' - if (id.length === size) return id - } - } - } -} -let customAlphabet = (alphabet, size) => customRandom(alphabet, size, random) -let nanoid = (size = 21) => { - fillPool(size) - let id = '' - for (let i = poolOffset - size; i < poolOffset; i++) { - id += urlAlphabet[pool[i] & 63] - } - return id -} -module.exports = { nanoid, customAlphabet, customRandom, urlAlphabet, random } diff --git a/node_modules/nanoid/index.d.ts b/node_modules/nanoid/index.d.ts deleted file mode 100644 index 9d2ae32..0000000 --- a/node_modules/nanoid/index.d.ts +++ /dev/null @@ -1,88 +0,0 @@ -/** - * Generate secure URL-friendly unique ID. - * - * By default, the ID will have 21 symbols to have a collision probability - * similar to UUID v4. - * - * ```js - * import { nanoid } from 'nanoid' - * model.id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqL" - * ``` - * - * @param size Size of the ID. The default size is 21. - * @returns A random string. - */ -export function nanoid(size?: number): string - -/** - * Generate secure unique ID with custom alphabet. - * - * Alphabet must contain 256 symbols or less. Otherwise, the generator - * will not be secure. - * - * @param alphabet Alphabet used to generate the ID. - * @param size Size of the ID. - * @returns A random string generator. - * - * ```js - * const { customAlphabet } = require('nanoid') - * const nanoid = customAlphabet('0123456789абвгдеё', 5) - * nanoid() //=> "8ё56а" - * ``` - */ -export function customAlphabet(alphabet: string, size: number): () => string - -/** - * Generate unique ID with custom random generator and alphabet. - * - * Alphabet must contain 256 symbols or less. Otherwise, the generator - * will not be secure. - * - * ```js - * import { customRandom } from 'nanoid/format' - * - * const nanoid = customRandom('abcdef', 5, size => { - * const random = [] - * for (let i = 0; i < size; i++) { - * random.push(randomByte()) - * } - * return random - * }) - * - * nanoid() //=> "fbaef" - * ``` - * - * @param alphabet Alphabet used to generate a random string. - * @param size Size of the random string. - * @param random A random bytes generator. - * @returns A random string generator. - */ -export function customRandom( - alphabet: string, - size: number, - random: (bytes: number) => Uint8Array -): () => string - -/** - * URL safe symbols. - * - * ```js - * import { urlAlphabet } from 'nanoid' - * const nanoid = customAlphabet(urlAlphabet, 10) - * nanoid() //=> "Uakgb_J5m9" - * ``` - */ -export const urlAlphabet: string - -/** - * Generate an array of random bytes collected from hardware noise. - * - * ```js - * import { customRandom, random } from 'nanoid' - * const nanoid = customRandom("abcdef", 5, random) - * ``` - * - * @param bytes Size of the array. - * @returns An array of random bytes. - */ -export function random(bytes: number): Uint8Array diff --git a/node_modules/nanoid/index.dev.js b/node_modules/nanoid/index.dev.js deleted file mode 100644 index cbe3260..0000000 --- a/node_modules/nanoid/index.dev.js +++ /dev/null @@ -1,62 +0,0 @@ -import { urlAlphabet } from './url-alphabet/index.js' -if (true) { - if ( - typeof navigator !== 'undefined' && - navigator.product === 'ReactNative' && - typeof crypto === 'undefined' - ) { - throw new Error( - 'React Native does not have a built-in secure random generator. ' + - 'If you don’t need unpredictable IDs use `nanoid/non-secure`. ' + - 'For secure IDs, import `react-native-get-random-values` ' + - 'before Nano ID.' - ) - } - if (typeof msCrypto !== 'undefined' && typeof crypto === 'undefined') { - throw new Error( - 'Import file with `if (!window.crypto) window.crypto = window.msCrypto`' + - ' before importing Nano ID to fix IE 11 support' - ) - } - if (typeof crypto === 'undefined') { - throw new Error( - 'Your browser does not have secure random generator. ' + - 'If you don’t need unpredictable IDs, you can use nanoid/non-secure.' - ) - } -} -let random = bytes => crypto.getRandomValues(new Uint8Array(bytes)) -let customRandom = (alphabet, size, getRandom) => { - let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1 - let step = -~((1.6 * mask * size) / alphabet.length) - return () => { - let id = '' - while (true) { - let bytes = getRandom(step) - let j = step - while (j--) { - id += alphabet[bytes[j] & mask] || '' - if (id.length === size) return id - } - } - } -} -let customAlphabet = (alphabet, size) => customRandom(alphabet, size, random) -let nanoid = (size = 21) => { - let id = '' - let bytes = crypto.getRandomValues(new Uint8Array(size)) - while (size--) { - let byte = bytes[size] & 63 - if (byte < 36) { - id += byte.toString(36) - } else if (byte < 62) { - id += (byte - 26).toString(36).toUpperCase() - } else if (byte < 63) { - id += '_' - } else { - id += '-' - } - } - return id -} -export { nanoid, customAlphabet, customRandom, urlAlphabet, random } diff --git a/node_modules/nanoid/index.js b/node_modules/nanoid/index.js deleted file mode 100644 index 76990cc..0000000 --- a/node_modules/nanoid/index.js +++ /dev/null @@ -1,44 +0,0 @@ -import crypto from 'crypto' -import { urlAlphabet } from './url-alphabet/index.js' -const POOL_SIZE_MULTIPLIER = 128 -let pool, poolOffset -let fillPool = bytes => { - if (!pool || pool.length < bytes) { - pool = Buffer.allocUnsafe(bytes * POOL_SIZE_MULTIPLIER) - crypto.randomFillSync(pool) - poolOffset = 0 - } else if (poolOffset + bytes > pool.length) { - crypto.randomFillSync(pool) - poolOffset = 0 - } - poolOffset += bytes -} -let random = bytes => { - fillPool(bytes) - return pool.subarray(poolOffset - bytes, poolOffset) -} -let customRandom = (alphabet, size, getRandom) => { - let mask = (2 << (31 - Math.clz32((alphabet.length - 1) | 1))) - 1 - let step = Math.ceil((1.6 * mask * size) / alphabet.length) - return () => { - let id = '' - while (true) { - let bytes = getRandom(step) - let i = step - while (i--) { - id += alphabet[bytes[i] & mask] || '' - if (id.length === size) return id - } - } - } -} -let customAlphabet = (alphabet, size) => customRandom(alphabet, size, random) -let nanoid = (size = 21) => { - fillPool(size) - let id = '' - for (let i = poolOffset - size; i < poolOffset; i++) { - id += urlAlphabet[pool[i] & 63] - } - return id -} -export { nanoid, customAlphabet, customRandom, urlAlphabet, random } diff --git a/node_modules/nanoid/index.prod.js b/node_modules/nanoid/index.prod.js deleted file mode 100644 index dc2703a..0000000 --- a/node_modules/nanoid/index.prod.js +++ /dev/null @@ -1,62 +0,0 @@ -import { urlAlphabet } from './url-alphabet/index.js' -if (false) { - if ( - typeof navigator !== 'undefined' && - navigator.product === 'ReactNative' && - typeof crypto === 'undefined' - ) { - throw new Error( - 'React Native does not have a built-in secure random generator. ' + - 'If you don’t need unpredictable IDs use `nanoid/non-secure`. ' + - 'For secure IDs, import `react-native-get-random-values` ' + - 'before Nano ID.' - ) - } - if (typeof msCrypto !== 'undefined' && typeof crypto === 'undefined') { - throw new Error( - 'Import file with `if (!window.crypto) window.crypto = window.msCrypto`' + - ' before importing Nano ID to fix IE 11 support' - ) - } - if (typeof crypto === 'undefined') { - throw new Error( - 'Your browser does not have secure random generator. ' + - 'If you don’t need unpredictable IDs, you can use nanoid/non-secure.' - ) - } -} -let random = bytes => crypto.getRandomValues(new Uint8Array(bytes)) -let customRandom = (alphabet, size, getRandom) => { - let mask = (2 << (Math.log(alphabet.length - 1) / Math.LN2)) - 1 - let step = -~((1.6 * mask * size) / alphabet.length) - return () => { - let id = '' - while (true) { - let bytes = getRandom(step) - let j = step - while (j--) { - id += alphabet[bytes[j] & mask] || '' - if (id.length === size) return id - } - } - } -} -let customAlphabet = (alphabet, size) => customRandom(alphabet, size, random) -let nanoid = (size = 21) => { - let id = '' - let bytes = crypto.getRandomValues(new Uint8Array(size)) - while (size--) { - let byte = bytes[size] & 63 - if (byte < 36) { - id += byte.toString(36) - } else if (byte < 62) { - id += (byte - 26).toString(36).toUpperCase() - } else if (byte < 63) { - id += '_' - } else { - id += '-' - } - } - return id -} -export { nanoid, customAlphabet, customRandom, urlAlphabet, random } diff --git a/node_modules/nanoid/nanoid.js b/node_modules/nanoid/nanoid.js deleted file mode 100644 index 5bbc489..0000000 --- a/node_modules/nanoid/nanoid.js +++ /dev/null @@ -1 +0,0 @@ -export let nanoid=(t=21)=>{let e="",r=crypto.getRandomValues(new Uint8Array(t));for(;t--;){let n=63&r[t];e+=n<36?n.toString(36):n<62?(n-26).toString(36).toUpperCase():n<63?"_":"-"}return e}; \ No newline at end of file diff --git a/node_modules/nanoid/non-secure/index.cjs b/node_modules/nanoid/non-secure/index.cjs deleted file mode 100644 index bd44482..0000000 --- a/node_modules/nanoid/non-secure/index.cjs +++ /dev/null @@ -1,21 +0,0 @@ -let urlAlphabet = - 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict' -let customAlphabet = (alphabet, size) => { - return () => { - let id = '' - let i = size - while (i--) { - id += alphabet[(Math.random() * alphabet.length) | 0] - } - return id - } -} -let nanoid = (size = 21) => { - let id = '' - let i = size - while (i--) { - id += urlAlphabet[(Math.random() * 64) | 0] - } - return id -} -module.exports = { nanoid, customAlphabet } diff --git a/node_modules/nanoid/non-secure/index.d.ts b/node_modules/nanoid/non-secure/index.d.ts deleted file mode 100644 index 84fc843..0000000 --- a/node_modules/nanoid/non-secure/index.d.ts +++ /dev/null @@ -1,30 +0,0 @@ -/** - * Generate URL-friendly unique ID. This method uses the non-secure - * predictable random generator with bigger collision probability. - * - * ```js - * import { nanoid } from 'nanoid/non-secure' - * model.id = nanoid() //=> "Uakgb_J5m9g-0JDMbcJqL" - * ``` - * - * @param size Size of the ID. The default size is 21. - * @returns A random string. - */ -export function nanoid(size?: number): string - -/** - * Generate URL-friendly unique ID based on the custom alphabet. - * This method uses the non-secure predictable random generator - * with bigger collision probability. - * - * @param alphabet Alphabet used to generate the ID. - * @param size Size of the ID. - * @returns A random string. - * - * ```js - * import { customAlphabet } from 'nanoid/non-secure' - * const nanoid = customAlphabet('0123456789абвгдеё', 5) - * model.id = //=> "8ё56а" - * ``` - */ -export function customAlphabet(alphabet: string, size: number): () => string diff --git a/node_modules/nanoid/non-secure/index.js b/node_modules/nanoid/non-secure/index.js deleted file mode 100644 index e39c479..0000000 --- a/node_modules/nanoid/non-secure/index.js +++ /dev/null @@ -1,21 +0,0 @@ -let urlAlphabet = - 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict' -let customAlphabet = (alphabet, size) => { - return () => { - let id = '' - let i = size - while (i--) { - id += alphabet[(Math.random() * alphabet.length) | 0] - } - return id - } -} -let nanoid = (size = 21) => { - let id = '' - let i = size - while (i--) { - id += urlAlphabet[(Math.random() * 64) | 0] - } - return id -} -export { nanoid, customAlphabet } diff --git a/node_modules/nanoid/non-secure/package.json b/node_modules/nanoid/non-secure/package.json deleted file mode 100644 index 9930d6a..0000000 --- a/node_modules/nanoid/non-secure/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "module", - "main": "index.cjs", - "module": "index.js", - "react-native": "index.js" -} \ No newline at end of file diff --git a/node_modules/nanoid/package.json b/node_modules/nanoid/package.json deleted file mode 100644 index ebb4b2a..0000000 --- a/node_modules/nanoid/package.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "name": "nanoid", - "version": "3.1.30", - "description": "A tiny (130 bytes), secure URL-friendly unique string ID generator", - "keywords": [ - "uuid", - "random", - "id", - "url" - ], - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - }, - "author": "Andrey Sitnik ", - "license": "MIT", - "repository": "ai/nanoid", - "browser": { - "./index.js": "./index.browser.js", - "./async/index.js": "./async/index.browser.js", - "./async/index.cjs": "./async/index.browser.cjs", - "./index.cjs": "./index.browser.cjs" - }, - "react-native": "index.js", - "bin": "./bin/nanoid.cjs", - "sideEffects": false, - "types": "./index.d.ts", - "type": "module", - "main": "index.cjs", - "module": "index.js", - "exports": { - ".": { - "browser": { - "development": "./index.dev.js", - "production": "./index.prod.js", - "default": "./index.prod.js" - }, - "require": "./index.cjs", - "import": "./index.js", - "default": "./index.js", - "types": "./index.d.ts" - }, - "./package.json": "./package.json", - "./async/package.json": "./async/package.json", - "./async": { - "browser": "./async/index.browser.js", - "require": "./async/index.cjs", - "import": "./async/index.js", - "default": "./async/index.js" - }, - "./non-secure/package.json": "./non-secure/package.json", - "./non-secure": { - "require": "./non-secure/index.cjs", - "import": "./non-secure/index.js", - "default": "./non-secure/index.js" - }, - "./url-alphabet/package.json": "./url-alphabet/package.json", - "./url-alphabet": { - "require": "./url-alphabet/index.cjs", - "import": "./url-alphabet/index.js", - "default": "./url-alphabet/index.js" - }, - "./index.d.ts": "./index.d.ts" - } -} \ No newline at end of file diff --git a/node_modules/nanoid/url-alphabet/index.cjs b/node_modules/nanoid/url-alphabet/index.cjs deleted file mode 100644 index 757b709..0000000 --- a/node_modules/nanoid/url-alphabet/index.cjs +++ /dev/null @@ -1,3 +0,0 @@ -let urlAlphabet = - 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict' -module.exports = { urlAlphabet } diff --git a/node_modules/nanoid/url-alphabet/index.js b/node_modules/nanoid/url-alphabet/index.js deleted file mode 100644 index c2782e5..0000000 --- a/node_modules/nanoid/url-alphabet/index.js +++ /dev/null @@ -1,3 +0,0 @@ -let urlAlphabet = - 'useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict' -export { urlAlphabet } diff --git a/node_modules/nanoid/url-alphabet/package.json b/node_modules/nanoid/url-alphabet/package.json deleted file mode 100644 index 9930d6a..0000000 --- a/node_modules/nanoid/url-alphabet/package.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "type": "module", - "main": "index.cjs", - "module": "index.js", - "react-native": "index.js" -} \ No newline at end of file diff --git a/node_modules/neataptic/.npmignore b/node_modules/neataptic/.npmignore deleted file mode 100644 index 3d6d538..0000000 --- a/node_modules/neataptic/.npmignore +++ /dev/null @@ -1,6 +0,0 @@ -# Debug -debug - -# Development files -node_modules -npm-debug.log diff --git a/node_modules/neataptic/.travis.yml b/node_modules/neataptic/.travis.yml deleted file mode 100644 index e33a3c8..0000000 --- a/node_modules/neataptic/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ - language: node_js - script: "npm run test:travis" - node_js: - - "node" - - "7.6" diff --git a/node_modules/neataptic/CONTRIBUTING.md b/node_modules/neataptic/CONTRIBUTING.md deleted file mode 100644 index a05f2c7..0000000 --- a/node_modules/neataptic/CONTRIBUTING.md +++ /dev/null @@ -1,59 +0,0 @@ -## Introduction - -Thank you for considering contributing to Neataptic! Neataptic is currently only -maintained by a single developer, so every little bit counts! There are many ways -you can contribute: updating the documentation, reporting a bug or creating a new -feature. We also stimulate the creation of projects using Neataptic; this allows us -to show how Neataptic can be used. - -## Setting up the dev environment -Setting up the developer environment is fairly easy: -1. Fork the repository (button on the topright corner of this page) -2. Clone the repository to your computer (clone from chrome [here](https://github.com/wagenaartje/neataptic)) -3. `cd` into the project directory, and run `npm install` - -And you are good to go! - -**PS**: we use the [Javascript Semistandard Style](https://github.com/Flet/semistandard)! - -## Bugs -Nobody likes them, and we understand that you want to get rid of them as soon as -possible, but to assure that the debugging proces runs smoothly we need to have -all the information possible about the bug. - -#### Reporting a bug -We need a couple of things to process a bug report efficiently: -1. The version (1.x.x) -2. The error log (this allows us to trace the source of the bug) -3. What you were trying to do (e.g. connecting a node to a node) -4. (_if possible_) a piece of code that allows us to reproduce the bug -5. (_optionally_) Operating system and browser - -#### Fixing a bug -When you encounter a bug and want to fix it, _create an issue first_. Then clearly -say that you will create a pull request yourself that fixes the bug. This makes sure -people are aware that the bug exists. - -What you have to provide in your pull request: -1. A link to the issue that describes the bug -2. (_if not in the issue yet_), a brief explanation of what was going wrong -3. How you fixed it -4. What the possible side-effects are of the code change - -And the pull request will be merged in no-time! - -## Features -Neataptic gets extended all the time! However we prefer qualitative over quantitative -features - anyone can add a new `Activation` method for example, but you have to ask -yourself if it really improves the project. But _always_ feel free to create a pull -request with new features, as long as you incorporate the following: -1. What feature you are adding (/improving) -2. A usage example of the new feature (in code!) -3. Why you think it adds something to Neataptic -4. Possible side-effects of the new feature - -Afterwards, there will be quick response - but the pull request may take some time to -be accepted, so we can give other contributors time to comment as well. - -PS: If you want to make big improvements/features, please create an issue or send -an e-mail to wagenaartje@protonmail.com diff --git a/node_modules/neataptic/LICENSE b/node_modules/neataptic/LICENSE deleted file mode 100644 index 79d9811..0000000 --- a/node_modules/neataptic/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright 2017 Thomas Wagenaar . Copyright for -portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a -part of project Synaptic. - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE diff --git a/node_modules/neataptic/README.md b/node_modules/neataptic/README.md deleted file mode 100644 index 6cc6e99..0000000 --- a/node_modules/neataptic/README.md +++ /dev/null @@ -1,130 +0,0 @@ - - -### Neataptic - - - - - - -
                  - -Neataptic offers flexible neural networks; neurons and synapses can be removed with a single line of code. No fixed architecture is required for neural networks to function at all. This flexibility allows networks to be shaped for your dataset through neuro-evolution, which is done using multiple threads. - -```js -// this network learns the XOR gate (through neuro-evolution) -var network = new Network(2,1); - -var trainingSet = [ - { input: [0,0], output: [0] }, - { input: [0,1], output: [1] }, - { input: [1,0], output: [1] }, - { input: [1,1], output: [0] } -]; - -await network.evolve(trainingSet, { - equal: true, - error: 0.03 - }); -``` - -Neataptic also backpropagates more than 5x faster than competitors. [Run the tests yourself](https://jsfiddle.net/tuet004f/11/). This is an example of regular training in Neataptic: - -```js -// this network learns the XOR gate (through backpropagation) -var network = new architect.Perceptron(2, 4, 1); - -// training set same as in above example -network.train(trainingSet, { - error: 0.01 -}); - -network.activate([1,1]); // 0.9824... -``` - -Use any of the 6 built-in networks with customisable sizes to create a network: - -```javascript -var myNetwork = new architect.LSTM(1, 10, 5, 1); -``` - -Or built your own network with pre-built layers: - -```javascript -var input = new Layer.Dense(2); -var hidden1 = new Layer.LSTM(5); -var hidden2 = new Layer.GRU(3); -var output = new Layer.Dense(1); - -input.connect(hidden1); -hidden1.connect(hidden2); -hidden2.connect(output); - -var myNetwork = architect.Construct([input, hidden1, hidden2, output]); -``` - -You can even built your network neuron-by-neuron using nodes and groups! - -
                  -Visit the wiki to get started -
                  -
                  -or play around with neural networks -
                  - - - -## Examples -Neural networks can be used for nearly anything; driving a car, playing a game and even to predict words! At this moment, -the website only displays a small amount of examples. If you have an interesting project that you want to share with other users -of Neataptic, feel free to create a pull request! - -
                  -Neuroevolution examples (supervised) -
                  -
                  -LSTM timeseries (supervised) -
                  -
                  -Color classification (supervised) -
                  -
                  -Agar.io-AI (unsupervised) -
                  -
                  -Target seeking AI (unsupervised) -
                  -
                  -Crossover playground -
                  -‌ - -## Usage -Head over to the [wiki](https://wagenaartje.github.io/neataptic/docs/) for detailed usage. If you want to visualise your graphs, head -over to the [graph](https://github.com/wagenaartje/neataptic/tree/master/graph) folder. - -## Install -Neataptic files are hosted by rawgit, just copy this link into the `` tag: - -```html - -``` - -Installing with node is also possible: - -```javascript -npm install neataptic -``` - -Make sure you have Node.js `v7.6` or higher installed! - -## Further notices -Parts of [Synaptic](https://github.com/cazala/synaptic) where used to develop -Neataptic. - -The neuro-evolution algorithm used is the [Instinct](https://medium.com/@ThomasWagenaar/neuro-evolution-on-steroids-82bd14ddc2f6) algorithm. - -
                  - -You made it all the way down! If you appreciate this repo and want to support the development of it, please consider donating :thumbsup: -[![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CXS3G8NHBYEZE) diff --git a/node_modules/neataptic/dist/neataptic.js b/node_modules/neataptic/dist/neataptic.js deleted file mode 100644 index b1eb7de..0000000 --- a/node_modules/neataptic/dist/neataptic.js +++ /dev/null @@ -1,4509 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("child_process"), require("os")); - else if(typeof define === 'function' && define.amd) - define(["child_process", "os"], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(require("child_process"), require("os")); - else - root["neataptic"] = factory(root["child_process"], root["os"]); -})(this, function(__WEBPACK_EXTERNAL_MODULE_21__, __WEBPACK_EXTERNAL_MODULE_25__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 10); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(8), - mutation: __webpack_require__(11), - selection: __webpack_require__(12), - crossover: __webpack_require__(13), - cost: __webpack_require__(14), - gating: __webpack_require__(15), - connection: __webpack_require__(16), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(1); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Activates the node without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state); - - for (i = 0; i < this.connections.gated.length; i++) { - this.connections.gated[i].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) conn.gater.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - node.squash = methods.activation[json.squash]; - - return node; -}; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(5); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(1); -var Neat = __webpack_require__(9); -var Node = __webpack_require__(2); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = i < this.input ? 'input' : 'output'; - this.nodes.push(new Node(type)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - - return output; - }, - - /** - * Activates the network without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].noTraceActivate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].noTraceActivate(); - output.push(activation); - } else { - this.nodes[i].noTraceActivate(); - } - } - - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target === 'undefined' || target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden'); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var allconnections = this.connections.concat(this.selfconns); - - var connection = allconnections[Math.floor(Math.random() * allconnections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (node.connections.self.weight === 0) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost = methods.cost.MSE) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.noTraceActivate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var amount = options.amount || 1; - - var threads = options.threads; - if (typeof threads === 'undefined') { - if (typeof window === 'undefined') { // Node.js - threads = __webpack_require__(25).cpus().length; - } else { // Browser - threads = navigator.hardwareConcurrency; - } - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - if (typeof window === 'undefined') { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.node.TestWorker(converted, cost)); - } - } else { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.browser.TestWorker(converted, cost)); - } - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(parseFloat(result)) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.selfconns = bestGenome.selfconns; - this.gates = bestGenome.gates; - - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (functionIndex === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - }, - - /** Activate a serialized network */ - activateSerializedNetwork: function (input, A, S, data, F) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - /** Deserializes a dataset to an array of arrays */ - deserializeDataSet: function (serializedSet) { - var set = []; - - var sampleSize = serializedSet[0] + serializedSet[1]; - for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) { - let input = []; - for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) { - input.push(serializedSet[j]); - } - let output = []; - for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) { - output.push(serializedSet[j]); - } - set.push(input); - set.push(output); - } - - return set; - }, - - /** A list of compiled activation functions in a certain order */ - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ] -}; - -multi.testSerializedSet = function (set, cost, A, S, data, F) { - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < set.length; i += 2) { - let output = multi.activateSerializedNetwork(set[i], A, S, data, F); - error += cost(set[i + 1], output); - } - - return error / (set.length / 2); -}; - -/* Export */ -for (var i in multi) { - module.exports[i] = multi[i]; -} - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(1); -var Layer = __webpack_require__(7); -var Node = __webpack_require__(2); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum, true); - } else { - this.nodes[i].propagate(rate, momentum, true, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(6); -var Node = __webpack_require__(2); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum, true); - } else { - this.nodes[i].propagate(rate, momentum, true, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) return fx; - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) return -2 * x * d; - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) return 1 / 2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(4); -var methods = __webpack_require__(0); -var config = __webpack_require__(1); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - this.maxNodes = options.maxNodes || Infinity; - this.maxConns = options.maxConns || Infinity; - this.maxGates = options.maxGates || Infinity; - - // Custom mutation selection function if given - this.selectMutationMethod = typeof options.mutationSelection === 'function' ? options.mutationSelection.bind(this) : this.selectMutationMethod; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = undefined; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (typeof this.population[this.population.length - 1].score === 'undefined') { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = undefined; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Selects a random mutation method for a genome according to the parameters - */ - selectMutationMethod: function (genome) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - - if (mutationMethod === methods.mutation.ADD_NODE && genome.nodes.length >= this.maxNodes) { - if (config.warnings) console.warn('maxNodes exceeded!'); - return; - } - - if (mutationMethod === methods.mutation.ADD_CONN && genome.connections.length >= this.maxConns) { - if (config.warnings) console.warn('maxConns exceeded!'); - return; - } - - if (mutationMethod === methods.mutation.ADD_GATE && genome.gates.length >= this.maxGates) { - if (config.warnings) console.warn('maxGates exceeded!'); - return; - } - - return mutationMethod; - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.selectMutationMethod(this.population[i]); - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - var i; - if (this.fitnessPopulation) { - if (this.clear) { - for (i = 0; i < this.population.length; i++) { - this.population[i].clear(); - } - } - await this.fitness(this.population); - } else { - for (i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - if (this.population[0].score < this.population[1].score) { - this.sort(); - } - - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(18), - Network: __webpack_require__(4), - config: __webpack_require__(1), - Group: __webpack_require__(6), - Layer: __webpack_require__(7), - Node: __webpack_require__(2), - Neat: __webpack_require__(9), - multi: __webpack_require__(5) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(8); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error / output.length; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { - name: 'OUTPUT' - }, - INPUT: { - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(4); -var Group = __webpack_require__(6); -var Layer = __webpack_require__(7); -var Node = __webpack_require__(2); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - node: { - TestWorker: __webpack_require__(20) - }, - browser: { - TestWorker: __webpack_require__(24) - } -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var cp = __webpack_require__(21); -var path = __webpack_require__(22); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - this.worker = cp.fork(path.join(__dirname, '/worker')); - - this.worker.send({ set: dataSet, cost: cost.name }); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: serialized[0], - states: serialized[1], - conns: serialized[2] - }; - - var _that = this.worker; - this.worker.on('message', function callback (e) { - _that.removeListener('message', callback); - resolve(e); - }); - - this.worker.send(data); - }); - }, - - terminate: function () { - this.worker.kill(); - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_21__; - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(23))) - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var multi = __webpack_require__(5); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: new Float64Array(serialized[0]).buffer, - states: new Float64Array(serialized[1]).buffer, - conns: new Float64Array(serialized[2]).buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var F = [${multi.activations.toString()}]; - var cost = ${cost.toString()}; - var multi = { - deserializeDataSet: ${multi.deserializeDataSet.toString()}, - testSerializedSet: ${multi.testSerializedSet.toString()}, - activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} - }; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - var A = new Float64Array(e.data.activations); - var S = new Float64Array(e.data.states); - var data = new Float64Array(e.data.conns); - - var error = multi.testSerializedSet(set, cost, A, S, data, F); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = multi.deserializeDataSet(new Float64Array(e.data.set)); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 25 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_25__; - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/dist/worker.js b/node_modules/neataptic/dist/worker.js deleted file mode 100644 index e0323d8..0000000 --- a/node_modules/neataptic/dist/worker.js +++ /dev/null @@ -1,20 +0,0 @@ -var { multi, methods } = require('../../../neataptic'); - -var set = []; -var cost; -var F = multi.activations; - -process.on('message', function (e) { - if (typeof e.set === 'undefined') { - var A = e.activations; - var S = e.states; - var data = e.conns; - - var result = multi.testSerializedSet(set, cost, A, S, data, F); - - process.send(result); - } else { - cost = methods.cost[e.cost]; - set = multi.deserializeDataSet(e.set); - } -}); diff --git a/node_modules/neataptic/docs/404.html b/node_modules/neataptic/docs/404.html deleted file mode 100644 index 4a487d7..0000000 --- a/node_modules/neataptic/docs/404.html +++ /dev/null @@ -1,86 +0,0 @@ - - - Neataptic.js - 404 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  -

                  404: Page not found

                  -

                  If something is wrong, please create an issue here!

                  -
                  -
                  -
                  - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/articles/agario/index.html b/node_modules/neataptic/docs/articles/agario/index.html deleted file mode 100644 index 0c5e16c..0000000 --- a/node_modules/neataptic/docs/articles/agario/index.html +++ /dev/null @@ -1,288 +0,0 @@ - - - Neataptic.js - Agar.io AI - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Agar.io AI

                  -

                  Edit on Github

                  -
                  -

                  Agar.io is quite a simple game to play... well, for humans it is. However is it just as simple for artificial agents? In this article I will tell you how I have constructed a genetic algorithm that evolves neural networks to play in an Agario.io-like environment. The following simulation shows agents that resulted from 1000+ generations of running the algorithm:

                  -
                  - -

                  Hover your mouse over a blob to see some more info! Source code here

                  -

                  As you might have noticed, the genomes are performing quite well, but far from perfect. The genomes shows human-like traits: searching food, avoiding bigger blobs and chasing smaller blobs. However sometimes one genome just runs into a bigger blob for no reason at all. That is because each genome can only see 3 other blobs and 3 food blobs. But above all, the settings of the GA are far from optimized. That is why I invite you to optimize the settings, and perform a pull request on this repo.

                  -

                  The making of

                  -

                  The code consists of 3 main parts: the field, the player and the genetic algorithm. In the following few paragraphs i'll go into depth on this topics, discussing my choices made. At the bottom of this article you will find a list of improvements I have thought of, but not made yet.

                  -

                  If you have any questions about the code in the linked repo, please create an issue on this repo.

                  -

                  The field

                  -

                  The field consists of 2 different objects: food and players. Food is stationary, and has no 'brain'. Every piece of food has a static feeding value. Once food has been eaten, it just moves to a new location on the field. Players on the other hand are capable of making decisions through neural networks. They slowly decay in size when not replenished (either by eating other players or food).

                  -

                  The field has no borders; when a blob hits the left wall, it will 'teleport' to the right wall. During tests with a bordered field, the entire population of genomes tended to stick to one of the walls without ever evolving to a more flexible population. However, having borderless walls comes with a problem of which a fix has not yet been implemented: genomes that are for example near the left wall, won't detect blobs that are close to the right wall - even though the distance between the blobs can be very small.

                  -

                  Some (configurable) settings:

                  -
                    -
                  • There is one food blob per ~2500 pixels
                  • -
                  • There is one player per ~12500 pixels
                  • -
                  -

                  The player

                  -

                  The player is a simplified version of the player in the real game. A genome can't split and shoot - it can only move. The output of each genomes brain consists of merely a movement direction and movement speed.

                  -

                  Genomes can't accelerate, they immediately adapt to the speed given by their brain. They can only eat other blobs when they are 10% bigger, and they can move freely through other blobs that are less than 10% bigger. Each genome will only see the 3 closest players and the 3 closest food blobs within a certain radius.

                  -

                  Some (configurable) settings:

                  -
                    -
                  • A player must be 10% bigger than a blob to eat it
                  • -
                  • The minimal area of a player is 400 pixels
                  • -
                  • The maximal area of a player is 10000 pixels
                  • -
                  • The detection radius is 150 pixels
                  • -
                  • A player can see up to 3 other players in its detection radius
                  • -
                  • A player can see up to 3 food blobs in its detection radius
                  • -
                  • The maximum speed of a player is 3px/frame
                  • -
                  • The minimal speed of a player is 0.6px/frame
                  • -
                  • Every frame, the player loses 0.2% of its mass
                  • -
                  -

                  The genetic algorithm

                  -

                  The genetic algorithm is the core of the AI. In the first frame, a certain amount of players are initialized with a neural network as brain. The brains represent the population of a generation. These brains are then evolved by putting the entire population in a single playing field and letting them compete against each other. The fittest brains are moved on the next generation, the less fit brains have a high chance of being removed.

                  -
                  neat.sort();
                  -var newPopulation = [];
                  -
                  -// Elitism
                  -for(var i = 0; i < neat.elitism; i++){
                  -  newPopulation.push(neat.population[i]);
                  -}
                  -
                  -// Breed the next individuals
                  -for(var i = 0; i < neat.popsize - neat.elitism; i++){
                  -  newPopulation.push(neat.getOffspring());
                  -}
                  -
                  -// Replace the old population with the new population
                  -neat.population = newPopulation;
                  -neat.mutate();
                  -
                  -neat.generation++;
                  -startEvaluation();
                  -
                  - -

                  The above code shows the code run when the evaluation is finished. It is very similar to the built-in evolve() function of Neataptic, however adapted to avoid a fitness function as all genomes must be evaluated at the same time.

                  -

                  The scoring of the genomes is quite easy: when a certain amount of iterations has been reached, each genome is ranked by their area. Better performing genomes have eaten more blobs, and thus have a bigger area. This scoring is identical to the scoring in Agar.io. I have experimented with other scoring systems, but lots of them stimulated small players to finish themselves off if their score was too low for a certain amount of time.

                  -

                  Some (configurable) settings:

                  -
                    -
                  • An evaluation runs for 1000 frames
                  • -
                  • The mutation rate is 0.3
                  • -
                  • The elitism is 10%
                  • -
                  • Each genome starts with 0 hidden nodes
                  • -
                  • All mutation methods are allowed
                  • -
                  -

                  Issues/future improvements

                  -

                  There are a couple of known issues. However, most of them linked are linked to a future improvement in some way or another.

                  -

                  Issues:

                  -
                    -
                  • Genomes tend to avoid hidden nodes (this is really bad)
                  • -
                  -

                  Future improvements:

                  -
                    -
                  • Players must be able to detect close players, even if they are on the other side of the field
                  • -
                  • Players/food should not be spawned at locations occupied by players
                  • -
                  • The genetic algorithm should be able to run without any visualization
                  • -
                  • .. tell me your idea!
                  • -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/articles/classifycolors/index.html b/node_modules/neataptic/docs/articles/classifycolors/index.html deleted file mode 100644 index f60a2f3..0000000 --- a/node_modules/neataptic/docs/articles/classifycolors/index.html +++ /dev/null @@ -1,296 +0,0 @@ - - - Neataptic.js - Classify colors - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Classify colors

                  -

                  Edit on Github

                  -
                  -

                  Classifying is something a neural network can do quite well. In this article -I will demonstrate how you can set up the evolution process of a neural network -that learns to classify colors with Neataptic.

                  -

                  Colors: - - - - - - - -

                  -

                  Start evolution

                  -
                  Iteration: 0                                                        Best-fitness: 0
                  - -
                  -
                  -

                  Set sorted by color

                  -
                  -
                  -
                  -
                  -

                  Set sorted by NN

                  -
                  -
                  -
                  -
                  - -
                  - -

                  How it works

                  -

                  The algorithm to this classification is actually pretty easy. One of my biggest -problem was generating the colors, however I stumbled upon this -Javascript library that allows you to generate colors randomly by name - exactly -what I needed (but it also created a problem, read below). So I used it to create -a training set:

                  -
                  function createSet(){
                  -  var set = [];
                  -
                  -  for(index in COLORS){
                  -    var color = COLORS[index];
                  -
                  -    var randomColors = randomColor({ hue : color, count: PER_COLOR, format: 'rgb'});
                  -
                  -    for(var random in randomColors){
                  -      var rgb = randomColors[random];
                  -      random = rgb.substring(4, rgb.length-1).replace(/ /g, '').split(',');
                  -      for(var y in random) random[y] = random[y]/255;
                  -
                  -      var output = Array.apply(null, Array(COLORS.length)).map(Number.prototype.valueOf, 0);
                  -      output[index] = 1;
                  -
                  -      set.push({ input: random, output: output, color: color, rgb: rgb});
                  -    }
                  -  }
                  -
                  -  return set;
                  -}
                  -
                  - -

                  COLORS is an array storing all color names in strings. The possible colors are -listed above. Next, we convert this rgb string to an array and normalize the -values between 0 and 1. Last of all, we normalize the colors using -one-hot encoding. -Please note that the colorand rgb object attributes are irrelevant for the algorithm.

                  -
                  network.evolve(set, {
                  -  iterations: 1,
                  -  mutationRate: 0.6,
                  -  elisitm: 5,
                  -  popSize: 100,
                  -  mutation: methods.mutation.FFW,
                  -  cost: methods.cost.MSE
                  -});
                  -
                  - -

                  Now we create the built-in genetic algorithm in neataptic.js. We define -that we want to use all possible mutation methods and set the mutation rate -higher than normal. Sprinkle in some elitism and double the default population -size. Experiment with the parameters yourself, maybe you'll find even better parameters!

                  -

                  The fitness function is the most vital part of the algorithm. It basically -calculates the Mean Squared Error -of the entire set. Neataptic saves the programming of this fitness calculation. -At the same time the default growth parameter is used, so the networks will -get penalized for being too large.

                  -

                  And putting together all this code will create a color classifier.

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/articles/index.html b/node_modules/neataptic/docs/articles/index.html deleted file mode 100644 index de7967a..0000000 --- a/node_modules/neataptic/docs/articles/index.html +++ /dev/null @@ -1,178 +0,0 @@ - - - Neataptic.js - Articles - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Articles

                  -

                  Edit on Github

                  -
                  -

                  Welcome to the articles page! Every now and then, articles will be posted here -showing for what kind of projects Neataptic could be used. Neataptic is -excellent for the development of AI for browser games for example.

                  -

                  If you want to post your own article here, feel free to create a pull request -or an isse on the repo page!

                  -
                  -
                  -
                  - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/articles/neuroevolution/index.html b/node_modules/neataptic/docs/articles/neuroevolution/index.html deleted file mode 100644 index 7aec311..0000000 --- a/node_modules/neataptic/docs/articles/neuroevolution/index.html +++ /dev/null @@ -1,277 +0,0 @@ - - - Neataptic.js - Neuroevolution - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Neuroevolution

                  -

                  Edit on Github

                  -
                  -

                  This page shows some neuro-evolution examples. Please note that not every example -may always be successful. More may be added in the future!

                  -
                  -
                  - 1: Uphill and downhill -
                  -
                  -

                  This neural network gets taught to increase the input by 0.2 until 1.0 is reached, then it must decrease the input by 2.0.

                  - - -
                  - - - -
                  - -
                  -
                  - -
                  -
                  - 2: Count to ten -
                  -
                  -

                  This neural network gets taught to wait 9 inputs of 0, to output 1 at input number 10.

                  - - -
                  - - - -
                  - -
                  -
                  - -
                  -
                  - 3: Vowel vs. consonants classification -
                  -
                  -

                  This neural network gets taught to classify if a letter of the alphabet is a vowel or not. The data is one-hot-encoded.

                  - - -
                  - - - -
                  - -
                  -
                  - - -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/articles/playground/index.html b/node_modules/neataptic/docs/articles/playground/index.html deleted file mode 100644 index e2a2150..0000000 --- a/node_modules/neataptic/docs/articles/playground/index.html +++ /dev/null @@ -1,290 +0,0 @@ - - - Neataptic.js - Playground - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Playground

                  -

                  Edit on Github

                  -
                  -
                  -
                  -
                  - -
                  -
                  - -
                  -
                  - -
                  -
                  -
                  -
                  - -
                  -
                  - -
                  -
                  - -
                  -
                  -
                  -
                  - -
                  -
                  - -
                  -
                  - -
                  -
                  -
                  -
                  - -
                  -
                  - -
                  -
                  - -
                  -
                  -
                  -
                  - -
                  -
                  - -
                  -
                  - -
                  -
                  -
                  - input1 - -
                  -
                  - input2 - -
                  -
                  -
                  - -
                  -
                  -
                  Output: 
                  - -
                  - -
                  -
                  - -
                  - -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/articles/targetseeking/index.html b/node_modules/neataptic/docs/articles/targetseeking/index.html deleted file mode 100644 index 9dbf857..0000000 --- a/node_modules/neataptic/docs/articles/targetseeking/index.html +++ /dev/null @@ -1,323 +0,0 @@ - - - Neataptic.js - Target-seeking AI - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Target-seeking AI

                  -

                  Edit on Github

                  -
                  -

                  In the simulation below, neural networks that have been evolved through roughly -100 generations try to seek a target. Their goal is to stay as close to the target -as possible at all times. If you want to see how one of these networks looks like, -check out the complete simulation.

                  -
                  -
                  - -

                  Click on the field to relocate the target! Source code here.

                  -

                  The neural agents are actually performing really well. At least one agent will have -'solved the problem' after roughly 20 generations. That is because the base of the solution -is quite easy: one of the inputs of the neural networks is the angle to the target, so all it -has to do is output some value that is similar to this input value. This can easily be done -through the identity activation function, but surprisingly, most agents in the simulation above -tend to avoid this function.

                  -

                  You can check out the topology of the networks here. -If you manage to evolve the genomes quicker or better than this simulation with different settings, please -perform a pull request on this repo.

                  -

                  The making of

                  -

                  In the previous article I have gone more into depth on the environment of the algorithm, but in this article -I will focus more on the settings and inputs/outputs of the algorithm itself.

                  -

                  If you have any questions about the code in the linked repo, please create an issue on this repo.

                  -

                  The agents

                  -

                  The agents' task is very simple. They have to get in the vicinity of the target which is set to about -100 pixels, once they are in that vicinity, each agents' score will be increased proportionally `(100 - dist)`` -to the distance. There is one extra though: for every node in the agents' network, the score of the agent will -be decreased. This has two reasons; 1. networks shouldn't overfit the solution and 2. having smaller networks -reduces computation power.

                  -

                  Agents have some kind of momentum. They don't have mass, but they do have acceleration, so it takes a small -amount of time for a agent to reach the top speed in a certain direction.

                  -

                  Each agent has the following inputs:

                  -
                    -
                  • Its own speed in the x-axis
                  • -
                  • Its own speed in the y-axis
                  • -
                  • The targets' speed in the x-axis
                  • -
                  • The targets' speed in the y-axis
                  • -
                  • The angle towards the target
                  • -
                  • The distance to the target
                  • -
                  -

                  The output of each agent is just the desired movement direction.

                  -

                  There is no kind of collision, except for the walls of the fields. In the future, it might be interesting to -add collisions between multiple agents and/or the target to reveal some new tactics. This would require the -agent to know the location of surrounding agents.

                  -

                  The target

                  -

                  The target is fairly easy. It's programmed to switch direction every now and then by a random amount. There -is one important thing however: the target moves with half the speed of the agents, this makes sure -that agents always have the ability to catch up with the target. Apart from that, the physics for the target -are similar to the agents' physics.

                  -

                  The genetic algorithm

                  -

                  The genetic algorithm is the core of the AI. In the first frame, a certain -amount of players are initialized with a neural network as brain. The brains -represent the population of a generation. These brains are then evolved by -putting the entire population in óne playing field and letting them compete -against each other. The fittest brains are moved on the next generation, -the less fit brains have a high chance of being removed.

                  -
                  // Networks shouldn't get too big
                  -for(var genome in neat.population){
                  -  genome = neat.population[genome];
                  -  genome.score -= genome.nodes.length * SCORE_RADIUS / 10;
                  -}
                  -
                  -// Sort the population by score
                  -neat.sort();
                  -
                  -// Draw the best genome
                  -drawGraph(neat.population[0].graph($('.best').width(), $('.best').height()), '.best', false);
                  -
                  -// Init new pop
                  -var newPopulation = [];
                  -
                  -// Elitism
                  -for(var i = 0; i < neat.elitism; i++){
                  -  newPopulation.push(neat.population[i]);
                  -}
                  -
                  -// Breed the next individuals
                  -for(var i = 0; i < neat.popsize - neat.elitism; i++){
                  -  newPopulation.push(neat.getOffspring());
                  -}
                  -
                  -// Replace the old population with the new population
                  -neat.population = newPopulation;
                  -neat.mutate();
                  -
                  -neat.generation++;
                  -startEvaluation();
                  -
                  - -

                  The above code shows the code run when the evaluation is finished. It is very similar -to the built-in evolve() function of Neataptic, however adapted to avoid a fitness -function as all genomes must be evaluated at the same time.

                  -

                  The scoring of the genomes is quite easy: when a certain amount of iterations has been reached, -each genome is ranked by their final score. Genomes with a higher score have a small amount of nodes -and have been close to the target throughout the iteration.

                  -

                  Some (configurable) settings:

                  -
                    -
                  • An evaluation runs for 250 frames
                  • -
                  • The mutation rate is 0.3
                  • -
                  • The elitism is 10%
                  • -
                  • Each genome starts with 0 hidden nodes
                  • -
                  • All mutation methods are allowed
                  • -
                  -

                  Issues/future improvements

                  - -

                  Forks

                  -
                    -
                  • corpr8's fork -gives each neural agent its own acceleration, as well as letting each arrow -remain in the same place after each generation. This creates a much more -'fluid' process.
                  • -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.10/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.10/neataptic.js deleted file mode 100644 index 3d00857..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.10/neataptic.js +++ /dev/null @@ -1,3353 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 17); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(16), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - this.derivative = 0; - this.bias = 0; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var connection in this.connections.in){ - connection = this.connections.in[connection]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(node.connections.self.gater == this ? node.old : 0); - influences[influences.length - 1] += conn.weight * conn.from.activation; - } - } - - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var i = 0; i < nodes.length; i++){ - var node = nodes[i]; - var influence = influences[i]; - - var index = connection.xtrace.nodes.indexOf(node); - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - - // Update the gains of the gates - for(var connection in this.connections.gated){ - this.connections.gated[connection].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, target) { - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for (var connection in this.connections.out) { - var connection = this.connections.out[connection]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Learning rate - rate = rate || .1; - - // Adjust all the node's incoming connections - for (var connection in this.connections.in) { - var connection = this.connections.in[connection]; - - var gradient = this.error.projected * connection.elegibility; - - for(var i = 0; i < connection.xtrace.nodes.length; i++){ - var node = connection.xtrace.nodes[i]; - var value = connection.xtrace.values[i]; - gradient += node.error.responsibility * value; - } - - gradient *= this.mask; - - connection.weight += rate * gradient; // Adjust weights - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i in this.connections.out){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var connection in connections){ - connection = connections[connection]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(conn in this.connections.out){ - conn = this.connections.out[conn]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(conn in this.connections.in){ - conn = this.connections.in[conn]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate); - } else { - this.nodes[i].propagate(rate, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate); - } else { - this.nodes[i].propagate(rate, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - this.connect(this.nodes[i], this.nodes[j]); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(node in this.nodes){ - if(this.nodes[node].type == 'input'){ - this.nodes[node].activate(input[node]); - } else if (this.nodes[node].type == 'output'){ - var activation = this.nodes[node].activate(); - output.push(activation); - } else { - if(training) this.nodes[node].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[node].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, target){ - this.nodes.reverse(); - target.reverse(); - - // Propagate nodes from end to start - for(node in this.nodes){ - switch(this.nodes[node].type){ - case('hidden'): - this.nodes[node].propagate(rate); - break; - case('output'): - this.nodes[node].propagate(rate, target[node]); - break; - } - } - - target.reverse(); - this.nodes.reverse(); - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to){ - var connections = from.connect(to); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var rate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - var currentRate = rate; - - // Splits the given rates, assigns it to chunks of iteration - var bucketSize = 0; - if(Array.isArray(rate)){ - bucketSize = Math.floor(iterations / rate.length); - } - - // Loops the training process - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // If the rate is a function, calculate the new rate - if(typeof rate === 'function'){ - currentRate = rate(iterations, error); - } - - error = 0; - - // Changes the rate depending on the iteration (if enabled) - if(bucketSize > 0) { - var currentBucket = Math.floor(iterations / bucketSize); - currentRate = rate[currentBucket] || currentRate; - } - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, costFunction) { - var errorSum = 0; - for (var train in set) { - var input = set[train].input; - var target = set[train].output; - - var output = this.activate(input, true); - this.propagate(currentRate, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var test in set) { - input = set[test].input; - target = set[test].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var node in this.nodes){ - this.nodes[node].bias = values.bias || this.nodes[node].bias; - this.nodes[node].squash = values.squash || this.nodes[node].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: error, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - 1 - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network of both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - if(i < network1.nodes.length && i < network2.nodes.length){ - var node = null; - if(i >= size-network1.output){ - while(node == null || node.type != 'output'){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } else { - while(node == null || (i < size-network1.output && node.type == 'output')){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } - - offspring.nodes.push(node); - } else if(i < network1.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network1.nodes[network1.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network1.nodes[i]); - } - } else if(i < network2.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network2.nodes[network2.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network2.nodes[i]); - } - } - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - if(data.to == network1.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - if(data.to == network2.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(item in list){ - if(list[item] instanceof Group){ - for(var node in list[item].nodes){ - nodes.push(list[item].nodes[node]); - } - } else if(list[item] instanceof Layer){ - for(var group in list[item].nodes){ - for(var node in list[item].nodes[group].nodes){ - nodes.push(list[item].nodes[group].nodes[node]); - } - } - } else if(list[item] instanceof Node){ - nodes.push(list[item]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var node in nodes){ - for(var conn in nodes[node].connections.out){ - network.connections.push(nodes[node].connections.out[conn]); - } - for(var conn in nodes[node].connections.gated){ - network.gates.push(nodes[node].connections.gated[conn]); - } - if(nodes[node].connections.self.weight != 0){ - network.selfconns.push(nodes[node].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Return the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || [Methods.Selection.FITNESS_PROPORTIONATE]; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || [Methods.Mutation.ADD_CONN, - Methods.Mutation.SUB_CONN, - Methods.Mutation.ADD_NODE, - Methods.Mutation.SUB_NODE, - Methods.Mutation.MOD_BIAS, - Methods.Mutation.MOD_WEIGHT, - Methods.Mutation.MOD_ACTIVATION]; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - parent1 = this.getParent(); - parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2, crossoverMethod); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - var selectionMethod = this.selection[Math.floor(Math.random() * this.selection.length)]; - switch(selectionMethod){ - case Selection.FITNESS_PROPORTIONATE: - var r = Math.floor(Selection.FITNESS_PROPORTIONATE.config(Math.random()) * this.popsize); - return this.population[r]; - break; - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - if (!derivate) - return 1 / (1 + Math.exp(-x)); - var fx = Activation.LOGISTIC(x); - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if (derivate) - return 1 - Math.pow(Activation.TANH(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i in output){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i in output){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE", - config: function(r){ return Math.pow(r,2); } - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.10/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.10/neataptic.min.js deleted file mode 100644 index d63f514..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.10/neataptic.min.js +++ /dev/null @@ -1,25 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=17)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(16),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.derivative=0,this.bias=0,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t in this.connections.in)t=this.connections.in[t],this.state+=t.from.activation*t.weight*t.gain;this.activation=this.squash(this.state)*this.mask,this.derivative=this.squash(this.state,!0);var o=[],e=[];for(var i in this.connections.gated){i=this.connections.gated[i];var s=i.to,r=o.indexOf(s);r>-1?e[r]+=i.weight*i.from.activation:(o.push(s),e.push(s.connections.self.gater==this?s.old:0),e[e.length-1]+=i.weight*i.from.activation)}for(var t in this.connections.in){t=this.connections.in[t],t.elegibility=this.connections.self.gain*this.connections.self.weight*t.elegibility+t.from.activation*t.gain;for(var a=0;a-1?t.xtrace.values[r]=s.connections.self.gain*s.connections.self.weight*t.xtrace.values[r]+this.derivative*t.elegibility*c:(t.xtrace.nodes.push(s),t.xtrace.values.push(this.derivative*t.elegibility*c))}}for(var t in this.connections.gated)this.connections.gated[t].gain=this.activation;return this.activation},propagate:function(n,t){var o=0;if("output"==this.type)this.error.responsibility=this.error.projected=t-this.activation;else{for(var e in this.connections.out){var e=this.connections.out[e],i=e.to;o+=i.error.responsibility*e.weight*e.gain}this.error.projected=this.derivative*o,o=0;for(var s in this.connections.gated){s=this.connections.gated[s];var i=s.to,r=i.connections.self.gater==this?i.old:0;r+=s.weight*s.from.activation,o+=i.error.responsibility*r}this.error.gated=this.derivative*o,this.error.responsibility=this.error.projected+this.error.gated}if("constant"!=this.type){n=n||.1;for(var e in this.connections.in){for(var e=this.connections.in[e],a=this.error.projected*e.elegibility,c=0;c=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n in this.connections.in)n=this.connections.in[n],n.elegibility=0,n.xtrace={nodes:[],values:[]};this.error.responsibility=this.error.projected=this.error.gated=0,this.old=this.state=this.activation=0},mutate:function(n){if(void 0===n)throw new Error("No mutate method given!");if(!n.name in i.Mutation)throw new Error("This method does not exist!");switch(n){case c.MOD_ACTIVATION:var t=n.allowed[(n.allowed.indexOf(this.squash)+Math.floor(Math.random()*(n.allowed.length-1))+1)%n.allowed.length];this.squash=t;break;case c.MOD_BIAS:var o=Math.random()*(n.max-n.min)+n.min;this.bias+=o}},isProjectingTo:function(n){for(conn in this.connections.out)if(conn=this.connections.out[conn],conn.to==n)return!0;return!1},isProjectedBy:function(n){for(conn in this.connections.in)if(conn=this.connections.in[conn],conn.from==n)return!0;return!1},toJSON:function(){return{bias:this.bias,type:this.type,squash:this.squash.name,mask:this.mask}}},t.fromJSON=function(n){var o=new t;o.bias=n.bias,o.type=n.type,o.mask=n.mask;for(squash in a)if(a[squash].name==n.squash){o.squash=a[squash];break}return o}}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={warnings:!0};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n,t,o){this.from=n,this.to=t,this.gain=1,this.weight=void 0===o?.2*Math.random()-.1:o,this.gater=null,this.elegibility=0,this.xtrace={nodes:[],values:[]}}n&&(n.exports=t),t.prototype={toJSON:function(){return{weight:this.weight}}},t.innovationID=function(n,t){return.5*(n+t)*(n+t+1)+t}}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n){this.nodes=[],this.connections={in:[],out:[],self:[]};for(var t=0;t=0;o--)void 0===t?this.nodes[o].propagate(n):this.nodes[o].propagate(n,t[o])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;o--)void 0===t?this.nodes[o].propagate(n):this.nodes[o].propagate(n,t[o])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var d in o){if(0==c.length)break;d=o[d];var l=Math.floor(Math.random()*c.length),f=c[l];this.gate(d,c[l]),c.splice(l,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var d=[],l=0;l1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.to)>this.nodes.indexOf(w.from)&&O.push(w);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],A=Math.random()*(n.max-n.min)+n.min;t.weight+=A;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],l=this.input;l1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.from)>this.nodes.indexOf(w.to)&&O.push(w);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),p=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),g=this.nodes[f],L=p.bias,M=p.squash;p.bias=g.bias,p.squash=g.squash,g.bias=L,g.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,d=t.clear||!1,l=t.dropout||0,p=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=l,f)var v=t.crossValidate.testSize,g=t.crossValidate.testError,m=Math.ceil((1-v)*n.length),O=n.slice(0,m),_=n.slice(m);var A=c,w=0;Array.isArray(c)&&(w=Math.floor(u/c.length));for(var N=0,T=1;T>i&&(0==u||N0){A=c[Math.floor(u/w)]||A}if(f?(this._trainSet(O,A,a),d&&this.clear(),T+=this.test(_,a).error,d&&this.clear()):(T+=this._trainSet(n,A,a),d&&this.clear(),T/=n.length),h)for(var L,M,E=n.length;E;L=Math.floor(Math.random()*E),M=n[--E],n[E]=n[L],n[L]=M);e&&N%e==0&&console.log("iteration",N,"error",T,"rate",A),p&&N%p.iterations==0&&p.function()}if(d&&this.clear(),l)for(var E=0;Eg&&(g=v,m=O),u&&p.generation%u==0&&console.log("generation",p.generation,"error",O.score,"cost error",v),d&&iteration%d.iterations==0&&d.function()}f&&m.clear();var _={error:v,generations:p.generation,time:Date.now()-l};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,_}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=n.nodes.length-1-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var d=0;d=f-n.output)for(;null==l||"output"!=l.type;)l=Math.random()>=.5?n.nodes[d]:o.nodes[d];else for(;null==l||d=.5?n.nodes[d]:o.nodes[d];r.nodes.push(l)}else d=f-n.output?r.nodes.push(n.nodes[n.nodes.length-(d-(f-n.output-1))]):r.nodes.push(n.nodes[d]):d=f-n.output?r.nodes.push(o.nodes[o.nodes.length-(d-(f-n.output-1))]):r.nodes.push(o.nodes[d]));for(l in r.nodes)r.nodes[l]=e.fromJSON(r.nodes[l].toJSON());var p={},v={},g=n.connections.concat(n.selfconns);for(m in g){var m=g[m],O={weight:m.weight,from:n.nodes.indexOf(m.from),to:n.nodes.indexOf(m.to),gater:n.nodes.indexOf(m.gater)};if(O.to==n.nodes.length-1){if(!(O.from=.5?w[m][0]:w[m][1];N.push(m)}if(a==c){for(m in p)N.push(p[m]);for(m in v)N.push(v[m])}else if(a>c)for(m in p)N.push(p[m]);else for(m in v)N.push(v[m]);for(m in N){var T=N[m];if(T.to=0;f--)"output"==e[f].type||e[f].connections.out.length+e[f].connections.gated.length==0?(e[f].type="output",o.output++,u.push(e[f]),e.splice(f,1)):"input"!=e[f].type&&e[f].connections.in.length||(e[f].type="input",o.input++,h.push(e[f]),e.splice(f,1));if(e=h.concat(e).concat(u),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a in e){for(var d in e[a].connections.out)o.connections.push(e[a].connections.out[d]);for(var d in e[a].connections.gated)o.gates.push(e[a].connections.gated[d]);0!=e[a].connections.self.weight&&o.selfconns.push(e[a].connections.self)}return o.nodes=e,o},Perceptron:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=[];t.push(new s(n[0]));for(var o=1;o0){var O=r.connect(v,e.Connection.ALL_TO_ALL);l.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=v.connect(v,e.Connection.ALL_TO_ELSE);l.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(v,e.Connection.ALL_TO_ALL);l.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(l,e.Connection.ALL_TO_ALL),o.connect(p,e.Connection.ALL_TO_ALL),o.connect(g,e.Connection.ALL_TO_ALL)),h.push(l),h.push(p),h.push(v),h.push(g),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){var o=0;for(var e in t)o-=n[e]*Math.log(Math.max(t[e],1e-15))+(1-n[e])*Math.log(1-Math.max(t[e],1e-15));return o},MSE:function(n,t){var o=0;for(var e in t)o+=Math.pow(n[e]-t[e],2);return o/t.length},BINARY:function(n,t){var o=0;for(var e in t)o+=Math.round(2*n[e])!=Math.round(2*t[e]);return o},MAE:function(n,t){var o=0;for(var e in t)o+=Math.abs(n[e]-t[e]);return o/t.length},MAPE:function(n,t){var o=0;for(var e in t)o+=Math.abs((t[e]-n[e])/Math.max(n[e],1e-15));return o/t.length},MSLE:function(n,t){var o=0;for(var e in t)o+=Math.log(Math.max(n[e],1e-15))-Math.log(Math.max(t[e],1e-15));return o},HINGE:function(n,t){var o=0;for(var e in t)o+=Math.max(0,1-n[e]*t[e]);return o}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={SINGLE_POINT:{name:"SINGLE_POINT",config:[.4]},TWO_POINT:{name:"TWO_POINT",config:[.4,.9]},UNIFORM:{name:"UNIFORM"},AVERAGE:{name:"AVERAGE"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={OUTPUT:{name:"OUTPUT"},INPUT:{name:"INPUT"},SELF:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t=o(10),e={ADD_NODE:{name:"ADD_NODE"},SUB_NODE:{name:"SUB_NODE",keep_gates:!0},ADD_CONN:{name:"ADD_CONN"},SUB_CONN:{name:"REMOVE_CONN"},MOD_WEIGHT:{name:"MOD_WEIGHT",min:-1,max:1},MOD_BIAS:{name:"MOD_BIAS",min:-1,max:1},MOD_ACTIVATION:{name:"MOD_ACTIVATION",mutateOutput:!0,allowed:[t.LOGISTIC,t.TANH,t.RELU,t.IDENTITY,t.STEP,t.SOFTSIGN,t.SINUSOID,t.GAUSSIAN,t.BENT_IDENTITY,t.BIPOLAR,t.BIPOLAR_SIGMOID,t.HARD_TANH,t.ABSOLUTE]},ADD_SELF_CONN:{name:"ADD_SELF_CONN"},SUB_SELF_CONN:{name:"SUB_SELF_CONN"},ADD_GATE:{name:"ADD_GATE"},SUB_GATE:{name:"SUB_GATE"},ADD_BACK_CONN:{name:"ADD_BACK_CONN"},SUB_BACK_CONN:{name:"SUB_BACK_CONN"},SWAP_NODES:{name:"SWAP_NODES"}};e.ALL=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION,e.ADD_GATE,e.SUB_GATE,e.ADD_SELF_CONN,e.SUB_SELF_CONN,e.ADD_BACK_CONN,e.SUB_BACK_CONN],e.FFW=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION],n&&(n.exports=e)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FITNESS_PROPORTIONATE:{name:"FITNESS_PROPORTIONATE",config:function(n){return Math.pow(n,2)}}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){var e,i,s={Node:o(2),Neat:o(9),Network:o(7),Methods:o(1),Architect:o(8),Group:o(5),Connection:o(4),Config:o(3),Layer:o(6)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.neataptic;s.ninja=function(){return window.neataptic=n,s}}(),window.neataptic=s)}])}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.11/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.11/neataptic.js deleted file mode 100644 index 3c55995..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.11/neataptic.js +++ /dev/null @@ -1,3413 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 17); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(16), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - this.derivative = 0; - this.bias = 0; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var connection in this.connections.in){ - connection = this.connections.in[connection]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(node.connections.self.gater == this ? node.old : 0); - influences[influences.length - 1] += conn.weight * conn.from.activation; - } - } - - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var i = 0; i < nodes.length; i++){ - var node = nodes[i]; - var influence = influences[i]; - - var index = connection.xtrace.nodes.indexOf(node); - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - - // Update the gains of the gates - for(var connection in this.connections.gated){ - this.connections.gated[connection].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, target) { - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for (var connection in this.connections.out) { - var connection = this.connections.out[connection]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Learning rate - rate = rate || .1; - - // Adjust all the node's incoming connections - for (var connection in this.connections.in) { - var connection = this.connections.in[connection]; - - var gradient = this.error.projected * connection.elegibility; - - for(var i = 0; i < connection.xtrace.nodes.length; i++){ - var node = connection.xtrace.nodes[i]; - var value = connection.xtrace.values[i]; - gradient += node.error.responsibility * value; - } - - gradient *= this.mask; - - connection.weight += rate * gradient; // Adjust weights - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i in this.connections.out){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var connection in connections){ - connection = connections[connection]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(conn in this.connections.out){ - conn = this.connections.out[conn]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(conn in this.connections.in){ - conn = this.connections.in[conn]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate); - } else { - this.nodes[i].propagate(rate, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate); - } else { - this.nodes[i].propagate(rate, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - this.connect(this.nodes[i], this.nodes[j]); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(node in this.nodes){ - if(this.nodes[node].type == 'input'){ - this.nodes[node].activate(input[node]); - } else if (this.nodes[node].type == 'output'){ - var activation = this.nodes[node].activate(); - output.push(activation); - } else { - if(training) this.nodes[node].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[node].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, target){ - this.nodes.reverse(); - target.reverse(); - - // Propagate nodes from end to start - for(node in this.nodes){ - switch(this.nodes[node].type){ - case('hidden'): - this.nodes[node].propagate(rate); - break; - case('output'): - this.nodes[node].propagate(rate, target[node]); - break; - } - } - - target.reverse(); - this.nodes.reverse(); - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to){ - var connections = from.connect(to); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var rate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - var currentRate = rate; - - // Splits the given rates, assigns it to chunks of iteration - var bucketSize = 0; - if(Array.isArray(rate)){ - bucketSize = Math.floor(iterations / rate.length); - } - - // Loops the training process - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // If the rate is a function, calculate the new rate - if(typeof rate === 'function'){ - currentRate = rate(iterations, error); - } - - error = 0; - - // Changes the rate depending on the iteration (if enabled) - if(bucketSize > 0) { - var currentBucket = Math.floor(iterations / bucketSize); - currentRate = rate[currentBucket] || currentRate; - } - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, costFunction) { - var errorSum = 0; - for (var train in set) { - var input = set[train].input; - var target = set[train].output; - - var output = this.activate(input, true); - this.propagate(currentRate, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var test in set) { - input = set[test].input; - target = set[test].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var node in this.nodes){ - this.nodes[node].bias = values.bias || this.nodes[node].bias; - this.nodes[node].squash = values.squash || this.nodes[node].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: error, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - 1 - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network of both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - if(i < network1.nodes.length && i < network2.nodes.length){ - var node = null; - if(i >= size-network1.output){ - while(node == null || node.type != 'output'){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } else { - while(node == null || (i < size-network1.output && node.type == 'output')){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } - - offspring.nodes.push(node); - } else if(i < network1.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network1.nodes[network1.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network1.nodes[i]); - } - } else if(i < network2.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network2.nodes[network2.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network2.nodes[i]); - } - } - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - if(data.to == network1.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - if(data.to == network2.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(item in list){ - if(list[item] instanceof Group){ - for(var node in list[item].nodes){ - nodes.push(list[item].nodes[node]); - } - } else if(list[item] instanceof Layer){ - for(var group in list[item].nodes){ - for(var node in list[item].nodes[group].nodes){ - nodes.push(list[item].nodes[group].nodes[node]); - } - } - } else if(list[item] instanceof Node){ - nodes.push(list[item]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var node in nodes){ - for(var conn in nodes[node].connections.out){ - network.connections.push(nodes[node].connections.out[conn]); - } - for(var conn in nodes[node].connections.gated){ - network.gates.push(nodes[node].connections.gated[conn]); - } - if(nodes[node].connections.self.weight != 0){ - network.selfconns.push(nodes[node].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Return the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || [Methods.Mutation.ADD_CONN, - Methods.Mutation.SUB_CONN, - Methods.Mutation.ADD_NODE, - Methods.Mutation.SUB_NODE, - Methods.Mutation.MOD_BIAS, - Methods.Mutation.MOD_WEIGHT, - Methods.Mutation.MOD_ACTIVATION]; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - parent1 = this.getParent(); - parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2, crossoverMethod); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(method.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - if (!derivate) - return 1 / (1 + Math.exp(-x)); - var fx = Activation.LOGISTIC(x); - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if (derivate) - return 1 - Math.pow(Activation.TANH(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i in output){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i in output){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "QUADRATIC", - power: 2 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.11/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.11/neataptic.min.js deleted file mode 100644 index 5c6da8f..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.11/neataptic.min.js +++ /dev/null @@ -1,25 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=17)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(16),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.derivative=0,this.bias=0,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t in this.connections.in)t=this.connections.in[t],this.state+=t.from.activation*t.weight*t.gain;this.activation=this.squash(this.state)*this.mask,this.derivative=this.squash(this.state,!0);var o=[],e=[];for(var i in this.connections.gated){i=this.connections.gated[i];var s=i.to,r=o.indexOf(s);r>-1?e[r]+=i.weight*i.from.activation:(o.push(s),e.push(s.connections.self.gater==this?s.old:0),e[e.length-1]+=i.weight*i.from.activation)}for(var t in this.connections.in){t=this.connections.in[t],t.elegibility=this.connections.self.gain*this.connections.self.weight*t.elegibility+t.from.activation*t.gain;for(var a=0;a-1?t.xtrace.values[r]=s.connections.self.gain*s.connections.self.weight*t.xtrace.values[r]+this.derivative*t.elegibility*c:(t.xtrace.nodes.push(s),t.xtrace.values.push(this.derivative*t.elegibility*c))}}for(var t in this.connections.gated)this.connections.gated[t].gain=this.activation;return this.activation},propagate:function(n,t){var o=0;if("output"==this.type)this.error.responsibility=this.error.projected=t-this.activation;else{for(var e in this.connections.out){var e=this.connections.out[e],i=e.to;o+=i.error.responsibility*e.weight*e.gain}this.error.projected=this.derivative*o,o=0;for(var s in this.connections.gated){s=this.connections.gated[s];var i=s.to,r=i.connections.self.gater==this?i.old:0;r+=s.weight*s.from.activation,o+=i.error.responsibility*r}this.error.gated=this.derivative*o,this.error.responsibility=this.error.projected+this.error.gated}if("constant"!=this.type){n=n||.1;for(var e in this.connections.in){for(var e=this.connections.in[e],a=this.error.projected*e.elegibility,c=0;c=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n in this.connections.in)n=this.connections.in[n],n.elegibility=0,n.xtrace={nodes:[],values:[]};this.error.responsibility=this.error.projected=this.error.gated=0,this.old=this.state=this.activation=0},mutate:function(n){if(void 0===n)throw new Error("No mutate method given!");if(!n.name in i.Mutation)throw new Error("This method does not exist!");switch(n){case c.MOD_ACTIVATION:var t=n.allowed[(n.allowed.indexOf(this.squash)+Math.floor(Math.random()*(n.allowed.length-1))+1)%n.allowed.length];this.squash=t;break;case c.MOD_BIAS:var o=Math.random()*(n.max-n.min)+n.min;this.bias+=o}},isProjectingTo:function(n){for(conn in this.connections.out)if(conn=this.connections.out[conn],conn.to==n)return!0;return!1},isProjectedBy:function(n){for(conn in this.connections.in)if(conn=this.connections.in[conn],conn.from==n)return!0;return!1},toJSON:function(){return{bias:this.bias,type:this.type,squash:this.squash.name,mask:this.mask}}},t.fromJSON=function(n){var o=new t;o.bias=n.bias,o.type=n.type,o.mask=n.mask;for(squash in a)if(a[squash].name==n.squash){o.squash=a[squash];break}return o}}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={warnings:!0};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n,t,o){this.from=n,this.to=t,this.gain=1,this.weight=void 0===o?.2*Math.random()-.1:o,this.gater=null,this.elegibility=0,this.xtrace={nodes:[],values:[]}}n&&(n.exports=t),t.prototype={toJSON:function(){return{weight:this.weight}}},t.innovationID=function(n,t){return.5*(n+t)*(n+t+1)+t}}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n){this.nodes=[],this.connections={in:[],out:[],self:[]};for(var t=0;t=0;o--)void 0===t?this.nodes[o].propagate(n):this.nodes[o].propagate(n,t[o])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;o--)void 0===t?this.nodes[o].propagate(n):this.nodes[o].propagate(n,t[o])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var d in o){if(0==c.length)break;d=o[d];var l=Math.floor(Math.random()*c.length),f=c[l];this.gate(d,c[l]),c.splice(l,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var d=[],l=0;l1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],w=Math.random()*(n.max-n.min)+n.min;t.weight+=w;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],l=this.input;l1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),p=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),g=this.nodes[f],L=p.bias,M=p.squash;p.bias=g.bias,p.squash=g.squash,g.bias=L,g.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,d=t.clear||!1,l=t.dropout||0,p=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=l,f)var v=t.crossValidate.testSize,g=t.crossValidate.testError,m=Math.ceil((1-v)*n.length),O=n.slice(0,m),_=n.slice(m);var w=c,A=0;Array.isArray(c)&&(A=Math.floor(u/c.length));for(var N=0,T=1;T>i&&(0==u||N0){w=c[Math.floor(u/A)]||w}if(f?(this._trainSet(O,w,a),d&&this.clear(),T+=this.test(_,a).error,d&&this.clear()):(T+=this._trainSet(n,w,a),d&&this.clear(),T/=n.length),h)for(var L,M,E=n.length;E;L=Math.floor(Math.random()*E),M=n[--E],n[E]=n[L],n[L]=M);e&&N%e==0&&console.log("iteration",N,"error",T,"rate",w),p&&N%p.iterations==0&&p.function()}if(d&&this.clear(),l)for(var E=0;Eg&&(g=v,m=O),u&&p.generation%u==0&&console.log("generation",p.generation,"error",O.score,"cost error",v),d&&iteration%d.iterations==0&&d.function()}f&&m.clear();var _={error:v,generations:p.generation,time:Date.now()-l};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,_}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=n.nodes.length-1-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var d=0;d=f-n.output)for(;null==l||"output"!=l.type;)l=Math.random()>=.5?n.nodes[d]:o.nodes[d];else for(;null==l||d=.5?n.nodes[d]:o.nodes[d];r.nodes.push(l)}else d=f-n.output?r.nodes.push(n.nodes[n.nodes.length-(d-(f-n.output-1))]):r.nodes.push(n.nodes[d]):d=f-n.output?r.nodes.push(o.nodes[o.nodes.length-(d-(f-n.output-1))]):r.nodes.push(o.nodes[d]));for(l in r.nodes)r.nodes[l]=e.fromJSON(r.nodes[l].toJSON());var p={},v={},g=n.connections.concat(n.selfconns);for(m in g){var m=g[m],O={weight:m.weight,from:n.nodes.indexOf(m.from),to:n.nodes.indexOf(m.to),gater:n.nodes.indexOf(m.gater)};if(O.to==n.nodes.length-1){if(!(O.from=.5?A[m][0]:A[m][1];N.push(m)}if(a==c){for(m in p)N.push(p[m]);for(m in v)N.push(v[m])}else if(a>c)for(m in p)N.push(p[m]);else for(m in v)N.push(v[m]);for(m in N){var T=N[m];if(T.to=0;f--)"output"==e[f].type||e[f].connections.out.length+e[f].connections.gated.length==0?(e[f].type="output",o.output++,u.push(e[f]),e.splice(f,1)):"input"!=e[f].type&&e[f].connections.in.length||(e[f].type="input",o.input++,h.push(e[f]),e.splice(f,1));if(e=h.concat(e).concat(u),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a in e){for(var d in e[a].connections.out)o.connections.push(e[a].connections.out[d]);for(var d in e[a].connections.gated)o.gates.push(e[a].connections.gated[d]);0!=e[a].connections.self.weight&&o.selfconns.push(e[a].connections.self)}return o.nodes=e,o},Perceptron:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=[];t.push(new s(n[0]));for(var o=1;o0){var O=r.connect(v,e.Connection.ALL_TO_ALL);l.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=v.connect(v,e.Connection.ALL_TO_ELSE);l.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(v,e.Connection.ALL_TO_ALL);l.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(l,e.Connection.ALL_TO_ALL),o.connect(p,e.Connection.ALL_TO_ALL),o.connect(g,e.Connection.ALL_TO_ALL)),h.push(l),h.push(p),h.push(v),h.push(g),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){var o=0;for(var e in t)o-=n[e]*Math.log(Math.max(t[e],1e-15))+(1-n[e])*Math.log(1-Math.max(t[e],1e-15));return o},MSE:function(n,t){var o=0;for(var e in t)o+=Math.pow(n[e]-t[e],2);return o/t.length},BINARY:function(n,t){var o=0;for(var e in t)o+=Math.round(2*n[e])!=Math.round(2*t[e]);return o},MAE:function(n,t){var o=0;for(var e in t)o+=Math.abs(n[e]-t[e]);return o/t.length},MAPE:function(n,t){var o=0;for(var e in t)o+=Math.abs((t[e]-n[e])/Math.max(n[e],1e-15));return o/t.length},MSLE:function(n,t){var o=0;for(var e in t)o+=Math.log(Math.max(n[e],1e-15))-Math.log(Math.max(t[e],1e-15));return o},HINGE:function(n,t){var o=0;for(var e in t)o+=Math.max(0,1-n[e]*t[e]);return o}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={SINGLE_POINT:{name:"SINGLE_POINT",config:[.4]},TWO_POINT:{name:"TWO_POINT",config:[.4,.9]},UNIFORM:{name:"UNIFORM"},AVERAGE:{name:"AVERAGE"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={OUTPUT:{name:"OUTPUT"},INPUT:{name:"INPUT"},SELF:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t=o(10),e={ADD_NODE:{name:"ADD_NODE"},SUB_NODE:{name:"SUB_NODE",keep_gates:!0},ADD_CONN:{name:"ADD_CONN"},SUB_CONN:{name:"REMOVE_CONN"},MOD_WEIGHT:{name:"MOD_WEIGHT",min:-1,max:1},MOD_BIAS:{name:"MOD_BIAS",min:-1,max:1},MOD_ACTIVATION:{name:"MOD_ACTIVATION",mutateOutput:!0,allowed:[t.LOGISTIC,t.TANH,t.RELU,t.IDENTITY,t.STEP,t.SOFTSIGN,t.SINUSOID,t.GAUSSIAN,t.BENT_IDENTITY,t.BIPOLAR,t.BIPOLAR_SIGMOID,t.HARD_TANH,t.ABSOLUTE]},ADD_SELF_CONN:{name:"ADD_SELF_CONN"},SUB_SELF_CONN:{name:"SUB_SELF_CONN"},ADD_GATE:{name:"ADD_GATE"},SUB_GATE:{name:"SUB_GATE"},ADD_BACK_CONN:{name:"ADD_BACK_CONN"},SUB_BACK_CONN:{name:"SUB_BACK_CONN"},SWAP_NODES:{name:"SWAP_NODES"}};e.ALL=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION,e.ADD_GATE,e.SUB_GATE,e.ADD_SELF_CONN,e.SUB_SELF_CONN,e.ADD_BACK_CONN,e.SUB_BACK_CONN],e.FFW=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION],n&&(n.exports=e)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FITNESS_PROPORTIONATE:{name:"FITNESS_PROPORTIONATE"},POWER:{name:"QUADRATIC",power:2},TOURNAMENT:{name:"TOURNAMENT",size:5,probability:.5}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){var e,i,s={Node:o(2),Neat:o(9),Network:o(7),Methods:o(1),Architect:o(8),Group:o(5),Connection:o(4),Config:o(3),Layer:o(6)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.neataptic;s.ninja=function(){return window.neataptic=n,s}}(),window.neataptic=s)}])}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.12/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.12/neataptic.js deleted file mode 100644 index e4e9c1f..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.12/neataptic.js +++ /dev/null @@ -1,3419 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 17); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(16), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - this.previousDeltaWeight = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - this.derivative = 0; - this.bias = 0; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var connection in this.connections.in){ - connection = this.connections.in[connection]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(node.connections.self.gater == this ? node.old : 0); - influences[influences.length - 1] += conn.weight * conn.from.activation; - } - } - - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var i = 0; i < nodes.length; i++){ - var node = nodes[i]; - var influence = influences[i]; - - var index = connection.xtrace.nodes.indexOf(node); - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - - // Update the gains of the gates - for(var connection in this.connections.gated){ - this.connections.gated[connection].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - // Error accumulator - var error = 0; - - momentum = momentum || 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for (var connection in this.connections.out) { - var connection = this.connections.out[connection]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Learning rate - rate = rate || .1; - - // Adjust all the node's incoming connections - for (var connection in this.connections.in) { - var connection = this.connections.in[connection]; - - var gradient = this.error.projected * connection.elegibility; - - for(var i = 0; i < connection.xtrace.nodes.length; i++){ - var node = connection.xtrace.nodes[i]; - var value = connection.xtrace.values[i]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask; - - connection.weight += deltaWeight + momentum * this.previousDeltaWeight; - - this.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i in this.connections.out){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var connection in connections){ - connection = connections[connection]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(conn in this.connections.out){ - conn = this.connections.out[conn]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(conn in this.connections.in){ - conn = this.connections.in[conn]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - this.connect(this.nodes[i], this.nodes[j]); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(node in this.nodes){ - if(this.nodes[node].type == 'input'){ - this.nodes[node].activate(input[node]); - } else if (this.nodes[node].type == 'output'){ - var activation = this.nodes[node].activate(); - output.push(activation); - } else { - if(training) this.nodes[node].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[node].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - this.nodes.reverse(); - target.reverse(); - - // Propagate nodes from end to start - for(node in this.nodes){ - switch(this.nodes[node].type){ - case('hidden'): - this.nodes[node].propagate(rate, momentum); - break; - case('output'): - this.nodes[node].propagate(rate, momentum, target[node]); - break; - } - } - - target.reverse(); - this.nodes.reverse(); - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to){ - var connections = from.connect(to); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var rate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - var currentRate = rate; - - // Splits the given rates, assigns it to chunks of iteration - var bucketSize = 0; - if(Array.isArray(rate)){ - bucketSize = Math.floor(iterations / rate.length); - } - - // Loops the training process - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // If the rate is a function, calculate the new rate - if(typeof rate === 'function'){ - currentRate = rate(iterations, error); - } - - error = 0; - - // Changes the rate depending on the iteration (if enabled) - if(bucketSize > 0) { - var currentBucket = Math.floor(iterations / bucketSize); - currentRate = rate[currentBucket] || currentRate; - } - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var train in set) { - var input = set[train].input; - var target = set[train].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var test in set) { - input = set[test].input; - target = set[test].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var node in this.nodes){ - this.nodes[node].bias = values.bias || this.nodes[node].bias; - this.nodes[node].squash = values.squash || this.nodes[node].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: error, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - 1 - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network of both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - if(i < network1.nodes.length && i < network2.nodes.length){ - var node = null; - if(i >= size-network1.output){ - while(node == null || node.type != 'output'){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } else { - while(node == null || (i < size-network1.output && node.type == 'output')){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } - - offspring.nodes.push(node); - } else if(i < network1.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network1.nodes[network1.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network1.nodes[i]); - } - } else if(i < network2.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network2.nodes[network2.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network2.nodes[i]); - } - } - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - if(data.to == network1.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - if(data.to == network2.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(item in list){ - if(list[item] instanceof Group){ - for(var node in list[item].nodes){ - nodes.push(list[item].nodes[node]); - } - } else if(list[item] instanceof Layer){ - for(var group in list[item].nodes){ - for(var node in list[item].nodes[group].nodes){ - nodes.push(list[item].nodes[group].nodes[node]); - } - } - } else if(list[item] instanceof Node){ - nodes.push(list[item]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var node in nodes){ - for(var conn in nodes[node].connections.out){ - network.connections.push(nodes[node].connections.out[conn]); - } - for(var conn in nodes[node].connections.gated){ - network.gates.push(nodes[node].connections.gated[conn]); - } - if(nodes[node].connections.self.weight != 0){ - network.selfconns.push(nodes[node].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Return the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || [Methods.Mutation.ADD_CONN, - Methods.Mutation.SUB_CONN, - Methods.Mutation.ADD_NODE, - Methods.Mutation.SUB_NODE, - Methods.Mutation.MOD_BIAS, - Methods.Mutation.MOD_WEIGHT, - Methods.Mutation.MOD_ACTIVATION]; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - parent1 = this.getParent(); - parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2, crossoverMethod); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - if (!derivate) - return 1 / (1 + Math.exp(-x)); - var fx = Activation.LOGISTIC(x); - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if (derivate) - return 1 - Math.pow(Activation.TANH(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i in output){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i in output){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.12/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.12/neataptic.min.js deleted file mode 100644 index 6842aa1..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.12/neataptic.min.js +++ /dev/null @@ -1,25 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=17)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(16),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaWeight=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.derivative=0,this.bias=0,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t in this.connections.in)t=this.connections.in[t],this.state+=t.from.activation*t.weight*t.gain;this.activation=this.squash(this.state)*this.mask,this.derivative=this.squash(this.state,!0);var o=[],e=[];for(var i in this.connections.gated){i=this.connections.gated[i];var s=i.to,r=o.indexOf(s);r>-1?e[r]+=i.weight*i.from.activation:(o.push(s),e.push(s.connections.self.gater==this?s.old:0),e[e.length-1]+=i.weight*i.from.activation)}for(var t in this.connections.in){t=this.connections.in[t],t.elegibility=this.connections.self.gain*this.connections.self.weight*t.elegibility+t.from.activation*t.gain;for(var a=0;a-1?t.xtrace.values[r]=s.connections.self.gain*s.connections.self.weight*t.xtrace.values[r]+this.derivative*t.elegibility*c:(t.xtrace.nodes.push(s),t.xtrace.values.push(this.derivative*t.elegibility*c))}}for(var t in this.connections.gated)this.connections.gated[t].gain=this.activation;return this.activation},propagate:function(n,t,o){var e=0;if(t=t||0,"output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i in this.connections.out){var i=this.connections.out[i],s=i.to;e+=s.error.responsibility*i.weight*i.gain}this.error.projected=this.derivative*e,e=0;for(var r in this.connections.gated){r=this.connections.gated[r];var s=r.to,a=s.connections.self.gater==this?s.old:0;a+=r.weight*r.from.activation,e+=s.error.responsibility*a}this.error.gated=this.derivative*e,this.error.responsibility=this.error.projected+this.error.gated}if("constant"!=this.type){n=n||.1;for(var i in this.connections.in){for(var i=this.connections.in[i],c=this.error.projected*i.elegibility,h=0;h=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n in this.connections.in)n=this.connections.in[n],n.elegibility=0,n.xtrace={nodes:[],values:[]};this.error.responsibility=this.error.projected=this.error.gated=0,this.old=this.state=this.activation=0},mutate:function(n){if(void 0===n)throw new Error("No mutate method given!");if(!n.name in i.Mutation)throw new Error("This method does not exist!");switch(n){case c.MOD_ACTIVATION:var t=n.allowed[(n.allowed.indexOf(this.squash)+Math.floor(Math.random()*(n.allowed.length-1))+1)%n.allowed.length];this.squash=t;break;case c.MOD_BIAS:var o=Math.random()*(n.max-n.min)+n.min;this.bias+=o}},isProjectingTo:function(n){for(conn in this.connections.out)if(conn=this.connections.out[conn],conn.to==n)return!0;return!1},isProjectedBy:function(n){for(conn in this.connections.in)if(conn=this.connections.in[conn],conn.from==n)return!0;return!1},toJSON:function(){return{bias:this.bias,type:this.type,squash:this.squash.name,mask:this.mask}}},t.fromJSON=function(n){var o=new t;o.bias=n.bias,o.type=n.type,o.mask=n.mask;for(squash in a)if(a[squash].name==n.squash){o.squash=a[squash];break}return o}}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={warnings:!0};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n,t,o){this.from=n,this.to=t,this.gain=1,this.weight=void 0===o?.2*Math.random()-.1:o,this.gater=null,this.elegibility=0,this.xtrace={nodes:[],values:[]}}n&&(n.exports=t),t.prototype={toJSON:function(){return{weight:this.weight}}},t.innovationID=function(n,t){return.5*(n+t)*(n+t+1)+t}}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n){this.nodes=[],this.connections={in:[],out:[],self:[]};for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var d=Math.floor(Math.random()*c.length),f=c[d];this.gate(l,c[d]),c.splice(d,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],d=0;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],w=Math.random()*(n.max-n.min)+n.min;t.weight+=w;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],d=this.input;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),p=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),g=this.nodes[f],L=p.bias,M=p.squash;p.bias=g.bias,p.squash=g.squash,g.bias=L,g.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,d=t.dropout||0,p=t.momentum||0,v=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=d,f)var g=t.crossValidate.testSize,m=t.crossValidate.testError,O=Math.ceil((1-g)*n.length),_=n.slice(0,O),w=n.slice(O);var A=c,N=0;Array.isArray(c)&&(N=Math.floor(u/c.length));for(var T=0,L=1;L>i&&(0==u||T0){A=c[Math.floor(u/N)]||A}if(f?(this._trainSet(_,A,p,a),l&&this.clear(),L+=this.test(w,a).error,l&&this.clear()):(L+=this._trainSet(n,A,p,a),l&&this.clear(),L/=n.length),h)for(var M,E,S=n.length;S;M=Math.floor(Math.random()*S),E=n[--S],n[S]=n[M],n[M]=E);e&&T%e==0&&console.log("iteration",T,"error",L,"rate",A),v&&T%v.iterations==0&&v.function()}if(l&&this.clear(),d)for(var S=0;Sg&&(g=v,m=O),u&&p.generation%u==0&&console.log("generation",p.generation,"error",O.score,"cost error",v),l&&iteration%l.iterations==0&&l.function()}f&&m.clear();var _={error:v,generations:p.generation,time:Date.now()-d};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,_}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=n.nodes.length-1-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=0;l=f-n.output)for(;null==d||"output"!=d.type;)d=Math.random()>=.5?n.nodes[l]:o.nodes[l];else for(;null==d||l=.5?n.nodes[l]:o.nodes[l];r.nodes.push(d)}else l=f-n.output?r.nodes.push(n.nodes[n.nodes.length-(l-(f-n.output-1))]):r.nodes.push(n.nodes[l]):l=f-n.output?r.nodes.push(o.nodes[o.nodes.length-(l-(f-n.output-1))]):r.nodes.push(o.nodes[l]));for(d in r.nodes)r.nodes[d]=e.fromJSON(r.nodes[d].toJSON());var p={},v={},g=n.connections.concat(n.selfconns);for(m in g){var m=g[m],O={weight:m.weight,from:n.nodes.indexOf(m.from),to:n.nodes.indexOf(m.to),gater:n.nodes.indexOf(m.gater)};if(O.to==n.nodes.length-1){if(!(O.from=.5?A[m][0]:A[m][1];N.push(m)}if(a==c){for(m in p)N.push(p[m]);for(m in v)N.push(v[m])}else if(a>c)for(m in p)N.push(p[m]);else for(m in v)N.push(v[m]);for(m in N){var T=N[m];if(T.to=0;f--)"output"==e[f].type||e[f].connections.out.length+e[f].connections.gated.length==0?(e[f].type="output",o.output++,u.push(e[f]),e.splice(f,1)):"input"!=e[f].type&&e[f].connections.in.length||(e[f].type="input",o.input++,h.push(e[f]),e.splice(f,1));if(e=h.concat(e).concat(u),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a in e){for(var l in e[a].connections.out)o.connections.push(e[a].connections.out[l]);for(var l in e[a].connections.gated)o.gates.push(e[a].connections.gated[l]);0!=e[a].connections.self.weight&&o.selfconns.push(e[a].connections.self)}return o.nodes=e,o},Perceptron:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=[];t.push(new s(n[0]));for(var o=1;o0){var O=r.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=v.connect(v,e.Connection.ALL_TO_ELSE);d.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(d,e.Connection.ALL_TO_ALL),o.connect(p,e.Connection.ALL_TO_ALL),o.connect(g,e.Connection.ALL_TO_ALL)),h.push(d),h.push(p),h.push(v),h.push(g),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){var o=0;for(var e in t)o-=n[e]*Math.log(Math.max(t[e],1e-15))+(1-n[e])*Math.log(1-Math.max(t[e],1e-15));return o},MSE:function(n,t){var o=0;for(var e in t)o+=Math.pow(n[e]-t[e],2);return o/t.length},BINARY:function(n,t){var o=0;for(var e in t)o+=Math.round(2*n[e])!=Math.round(2*t[e]);return o},MAE:function(n,t){var o=0;for(var e in t)o+=Math.abs(n[e]-t[e]);return o/t.length},MAPE:function(n,t){var o=0;for(var e in t)o+=Math.abs((t[e]-n[e])/Math.max(n[e],1e-15));return o/t.length},MSLE:function(n,t){var o=0;for(var e in t)o+=Math.log(Math.max(n[e],1e-15))-Math.log(Math.max(t[e],1e-15));return o},HINGE:function(n,t){var o=0;for(var e in t)o+=Math.max(0,1-n[e]*t[e]);return o}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={SINGLE_POINT:{name:"SINGLE_POINT",config:[.4]},TWO_POINT:{name:"TWO_POINT",config:[.4,.9]},UNIFORM:{name:"UNIFORM"},AVERAGE:{name:"AVERAGE"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={OUTPUT:{name:"OUTPUT"},INPUT:{name:"INPUT"},SELF:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t=o(10),e={ADD_NODE:{name:"ADD_NODE"},SUB_NODE:{name:"SUB_NODE",keep_gates:!0},ADD_CONN:{name:"ADD_CONN"},SUB_CONN:{name:"REMOVE_CONN"},MOD_WEIGHT:{name:"MOD_WEIGHT",min:-1,max:1},MOD_BIAS:{name:"MOD_BIAS",min:-1,max:1},MOD_ACTIVATION:{name:"MOD_ACTIVATION",mutateOutput:!0,allowed:[t.LOGISTIC,t.TANH,t.RELU,t.IDENTITY,t.STEP,t.SOFTSIGN,t.SINUSOID,t.GAUSSIAN,t.BENT_IDENTITY,t.BIPOLAR,t.BIPOLAR_SIGMOID,t.HARD_TANH,t.ABSOLUTE]},ADD_SELF_CONN:{name:"ADD_SELF_CONN"},SUB_SELF_CONN:{name:"SUB_SELF_CONN"},ADD_GATE:{name:"ADD_GATE"},SUB_GATE:{name:"SUB_GATE"},ADD_BACK_CONN:{name:"ADD_BACK_CONN"},SUB_BACK_CONN:{name:"SUB_BACK_CONN"},SWAP_NODES:{name:"SWAP_NODES"}};e.ALL=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION,e.ADD_GATE,e.SUB_GATE,e.ADD_SELF_CONN,e.SUB_SELF_CONN,e.ADD_BACK_CONN,e.SUB_BACK_CONN],e.FFW=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION],n&&(n.exports=e)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FITNESS_PROPORTIONATE:{name:"FITNESS_PROPORTIONATE"},POWER:{name:"POWER",power:4},TOURNAMENT:{name:"TOURNAMENT",size:5,probability:.5}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){var e,i,s={Node:o(2),Neat:o(9),Network:o(7),Methods:o(1),Architect:o(8),Group:o(5),Connection:o(4),Config:o(3),Layer:o(6)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.neataptic;s.ninja=function(){return window.neataptic=n,s}}(),window.neataptic=s)}])}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.13/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.13/neataptic.js deleted file mode 100644 index a692540..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.13/neataptic.js +++ /dev/null @@ -1,3419 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 17); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(16), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - this.previousDeltaWeight = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - this.derivative = 0; - this.bias = 0; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var connection in this.connections.in){ - connection = this.connections.in[connection]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(node.connections.self.gater == this ? node.old : 0); - influences[influences.length - 1] += conn.weight * conn.from.activation; - } - } - - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var i = 0; i < nodes.length; i++){ - var node = nodes[i]; - var influence = influences[i]; - - var index = connection.xtrace.nodes.indexOf(node); - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - - // Update the gains of the gates - for(var connection in this.connections.gated){ - this.connections.gated[connection].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - // Error accumulator - var error = 0; - - momentum = momentum || 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for (var connection in this.connections.out) { - var connection = this.connections.out[connection]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Learning rate - rate = rate || .1; - - // Adjust all the node's incoming connections - for (var connection in this.connections.in) { - var connection = this.connections.in[connection]; - - var gradient = this.error.projected * connection.elegibility; - - for(var i = 0; i < connection.xtrace.nodes.length; i++){ - var node = connection.xtrace.nodes[i]; - var value = connection.xtrace.values[i]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask; - - connection.weight += deltaWeight + momentum * this.previousDeltaWeight; - - this.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i in this.connections.out){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var connection in connections){ - connection = connections[connection]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(conn in this.connections.out){ - conn = this.connections.out[conn]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(conn in this.connections.in){ - conn = this.connections.in[conn]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - this.connect(this.nodes[i], this.nodes[j]); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(node in this.nodes){ - if(this.nodes[node].type == 'input'){ - this.nodes[node].activate(input[node]); - } else if (this.nodes[node].type == 'output'){ - var activation = this.nodes[node].activate(); - output.push(activation); - } else { - if(training) this.nodes[node].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[node].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - this.nodes.reverse(); - target.reverse(); - - // Propagate nodes from end to start - for(node in this.nodes){ - switch(this.nodes[node].type){ - case('hidden'): - this.nodes[node].propagate(rate, momentum); - break; - case('output'): - this.nodes[node].propagate(rate, momentum, target[node]); - break; - } - } - - target.reverse(); - this.nodes.reverse(); - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to){ - var connections = from.connect(to); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var rate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - var currentRate = rate; - - // Splits the given rates, assigns it to chunks of iteration - var bucketSize = 0; - if(Array.isArray(rate)){ - bucketSize = Math.floor(iterations / rate.length); - } - - // Loops the training process - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // If the rate is a function, calculate the new rate - if(typeof rate === 'function'){ - currentRate = rate(iterations, error); - } - - error = 0; - - // Changes the rate depending on the iteration (if enabled) - if(bucketSize > 0) { - var currentBucket = Math.floor(iterations / bucketSize); - currentRate = rate[currentBucket] || currentRate; - } - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var train in set) { - var input = set[train].input; - var target = set[train].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var test in set) { - input = set[test].input; - target = set[test].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var node in this.nodes){ - this.nodes[node].bias = values.bias || this.nodes[node].bias; - this.nodes[node].squash = values.squash || this.nodes[node].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: error, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - 1 - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network of both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - if(i < network1.nodes.length && i < network2.nodes.length){ - var node = null; - if(i >= size-network1.output){ - while(node == null || node.type != 'output'){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } else { - while(node == null || (i < size-network1.output && node.type == 'output')){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } - - offspring.nodes.push(node); - } else if(i < network1.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network1.nodes[network1.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network1.nodes[i]); - } - } else if(i < network2.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network2.nodes[network2.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network2.nodes[i]); - } - } - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - if(data.to == network1.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - if(data.to == network2.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(item in list){ - if(list[item] instanceof Group){ - for(var node in list[item].nodes){ - nodes.push(list[item].nodes[node]); - } - } else if(list[item] instanceof Layer){ - for(var group in list[item].nodes){ - for(var node in list[item].nodes[group].nodes){ - nodes.push(list[item].nodes[group].nodes[node]); - } - } - } else if(list[item] instanceof Node){ - nodes.push(list[item]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var node in nodes){ - for(var conn in nodes[node].connections.out){ - network.connections.push(nodes[node].connections.out[conn]); - } - for(var conn in nodes[node].connections.gated){ - network.gates.push(nodes[node].connections.gated[conn]); - } - if(nodes[node].connections.self.weight != 0){ - network.selfconns.push(nodes[node].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Return the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || [Methods.Mutation.ADD_CONN, - Methods.Mutation.SUB_CONN, - Methods.Mutation.ADD_NODE, - Methods.Mutation.SUB_NODE, - Methods.Mutation.MOD_BIAS, - Methods.Mutation.MOD_WEIGHT, - Methods.Mutation.MOD_ACTIVATION]; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - parent1 = this.getParent(); - parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2, crossoverMethod); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - if (!derivate) - return 1 / (1 + Math.exp(-x)); - var fx = Activation.LOGISTIC(x); - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if (derivate) - return 1 - Math.pow(Activation.TANH(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i in output){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i in output){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.13/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.13/neataptic.min.js deleted file mode 100644 index 6842aa1..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.13/neataptic.min.js +++ /dev/null @@ -1,25 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=17)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(16),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaWeight=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.derivative=0,this.bias=0,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t in this.connections.in)t=this.connections.in[t],this.state+=t.from.activation*t.weight*t.gain;this.activation=this.squash(this.state)*this.mask,this.derivative=this.squash(this.state,!0);var o=[],e=[];for(var i in this.connections.gated){i=this.connections.gated[i];var s=i.to,r=o.indexOf(s);r>-1?e[r]+=i.weight*i.from.activation:(o.push(s),e.push(s.connections.self.gater==this?s.old:0),e[e.length-1]+=i.weight*i.from.activation)}for(var t in this.connections.in){t=this.connections.in[t],t.elegibility=this.connections.self.gain*this.connections.self.weight*t.elegibility+t.from.activation*t.gain;for(var a=0;a-1?t.xtrace.values[r]=s.connections.self.gain*s.connections.self.weight*t.xtrace.values[r]+this.derivative*t.elegibility*c:(t.xtrace.nodes.push(s),t.xtrace.values.push(this.derivative*t.elegibility*c))}}for(var t in this.connections.gated)this.connections.gated[t].gain=this.activation;return this.activation},propagate:function(n,t,o){var e=0;if(t=t||0,"output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i in this.connections.out){var i=this.connections.out[i],s=i.to;e+=s.error.responsibility*i.weight*i.gain}this.error.projected=this.derivative*e,e=0;for(var r in this.connections.gated){r=this.connections.gated[r];var s=r.to,a=s.connections.self.gater==this?s.old:0;a+=r.weight*r.from.activation,e+=s.error.responsibility*a}this.error.gated=this.derivative*e,this.error.responsibility=this.error.projected+this.error.gated}if("constant"!=this.type){n=n||.1;for(var i in this.connections.in){for(var i=this.connections.in[i],c=this.error.projected*i.elegibility,h=0;h=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n in this.connections.in)n=this.connections.in[n],n.elegibility=0,n.xtrace={nodes:[],values:[]};this.error.responsibility=this.error.projected=this.error.gated=0,this.old=this.state=this.activation=0},mutate:function(n){if(void 0===n)throw new Error("No mutate method given!");if(!n.name in i.Mutation)throw new Error("This method does not exist!");switch(n){case c.MOD_ACTIVATION:var t=n.allowed[(n.allowed.indexOf(this.squash)+Math.floor(Math.random()*(n.allowed.length-1))+1)%n.allowed.length];this.squash=t;break;case c.MOD_BIAS:var o=Math.random()*(n.max-n.min)+n.min;this.bias+=o}},isProjectingTo:function(n){for(conn in this.connections.out)if(conn=this.connections.out[conn],conn.to==n)return!0;return!1},isProjectedBy:function(n){for(conn in this.connections.in)if(conn=this.connections.in[conn],conn.from==n)return!0;return!1},toJSON:function(){return{bias:this.bias,type:this.type,squash:this.squash.name,mask:this.mask}}},t.fromJSON=function(n){var o=new t;o.bias=n.bias,o.type=n.type,o.mask=n.mask;for(squash in a)if(a[squash].name==n.squash){o.squash=a[squash];break}return o}}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={warnings:!0};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n,t,o){this.from=n,this.to=t,this.gain=1,this.weight=void 0===o?.2*Math.random()-.1:o,this.gater=null,this.elegibility=0,this.xtrace={nodes:[],values:[]}}n&&(n.exports=t),t.prototype={toJSON:function(){return{weight:this.weight}}},t.innovationID=function(n,t){return.5*(n+t)*(n+t+1)+t}}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n){this.nodes=[],this.connections={in:[],out:[],self:[]};for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var d=Math.floor(Math.random()*c.length),f=c[d];this.gate(l,c[d]),c.splice(d,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],d=0;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],w=Math.random()*(n.max-n.min)+n.min;t.weight+=w;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],d=this.input;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),p=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),g=this.nodes[f],L=p.bias,M=p.squash;p.bias=g.bias,p.squash=g.squash,g.bias=L,g.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,d=t.dropout||0,p=t.momentum||0,v=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=d,f)var g=t.crossValidate.testSize,m=t.crossValidate.testError,O=Math.ceil((1-g)*n.length),_=n.slice(0,O),w=n.slice(O);var A=c,N=0;Array.isArray(c)&&(N=Math.floor(u/c.length));for(var T=0,L=1;L>i&&(0==u||T0){A=c[Math.floor(u/N)]||A}if(f?(this._trainSet(_,A,p,a),l&&this.clear(),L+=this.test(w,a).error,l&&this.clear()):(L+=this._trainSet(n,A,p,a),l&&this.clear(),L/=n.length),h)for(var M,E,S=n.length;S;M=Math.floor(Math.random()*S),E=n[--S],n[S]=n[M],n[M]=E);e&&T%e==0&&console.log("iteration",T,"error",L,"rate",A),v&&T%v.iterations==0&&v.function()}if(l&&this.clear(),d)for(var S=0;Sg&&(g=v,m=O),u&&p.generation%u==0&&console.log("generation",p.generation,"error",O.score,"cost error",v),l&&iteration%l.iterations==0&&l.function()}f&&m.clear();var _={error:v,generations:p.generation,time:Date.now()-d};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,_}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=n.nodes.length-1-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=0;l=f-n.output)for(;null==d||"output"!=d.type;)d=Math.random()>=.5?n.nodes[l]:o.nodes[l];else for(;null==d||l=.5?n.nodes[l]:o.nodes[l];r.nodes.push(d)}else l=f-n.output?r.nodes.push(n.nodes[n.nodes.length-(l-(f-n.output-1))]):r.nodes.push(n.nodes[l]):l=f-n.output?r.nodes.push(o.nodes[o.nodes.length-(l-(f-n.output-1))]):r.nodes.push(o.nodes[l]));for(d in r.nodes)r.nodes[d]=e.fromJSON(r.nodes[d].toJSON());var p={},v={},g=n.connections.concat(n.selfconns);for(m in g){var m=g[m],O={weight:m.weight,from:n.nodes.indexOf(m.from),to:n.nodes.indexOf(m.to),gater:n.nodes.indexOf(m.gater)};if(O.to==n.nodes.length-1){if(!(O.from=.5?A[m][0]:A[m][1];N.push(m)}if(a==c){for(m in p)N.push(p[m]);for(m in v)N.push(v[m])}else if(a>c)for(m in p)N.push(p[m]);else for(m in v)N.push(v[m]);for(m in N){var T=N[m];if(T.to=0;f--)"output"==e[f].type||e[f].connections.out.length+e[f].connections.gated.length==0?(e[f].type="output",o.output++,u.push(e[f]),e.splice(f,1)):"input"!=e[f].type&&e[f].connections.in.length||(e[f].type="input",o.input++,h.push(e[f]),e.splice(f,1));if(e=h.concat(e).concat(u),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a in e){for(var l in e[a].connections.out)o.connections.push(e[a].connections.out[l]);for(var l in e[a].connections.gated)o.gates.push(e[a].connections.gated[l]);0!=e[a].connections.self.weight&&o.selfconns.push(e[a].connections.self)}return o.nodes=e,o},Perceptron:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=[];t.push(new s(n[0]));for(var o=1;o0){var O=r.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=v.connect(v,e.Connection.ALL_TO_ELSE);d.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(d,e.Connection.ALL_TO_ALL),o.connect(p,e.Connection.ALL_TO_ALL),o.connect(g,e.Connection.ALL_TO_ALL)),h.push(d),h.push(p),h.push(v),h.push(g),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){var o=0;for(var e in t)o-=n[e]*Math.log(Math.max(t[e],1e-15))+(1-n[e])*Math.log(1-Math.max(t[e],1e-15));return o},MSE:function(n,t){var o=0;for(var e in t)o+=Math.pow(n[e]-t[e],2);return o/t.length},BINARY:function(n,t){var o=0;for(var e in t)o+=Math.round(2*n[e])!=Math.round(2*t[e]);return o},MAE:function(n,t){var o=0;for(var e in t)o+=Math.abs(n[e]-t[e]);return o/t.length},MAPE:function(n,t){var o=0;for(var e in t)o+=Math.abs((t[e]-n[e])/Math.max(n[e],1e-15));return o/t.length},MSLE:function(n,t){var o=0;for(var e in t)o+=Math.log(Math.max(n[e],1e-15))-Math.log(Math.max(t[e],1e-15));return o},HINGE:function(n,t){var o=0;for(var e in t)o+=Math.max(0,1-n[e]*t[e]);return o}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={SINGLE_POINT:{name:"SINGLE_POINT",config:[.4]},TWO_POINT:{name:"TWO_POINT",config:[.4,.9]},UNIFORM:{name:"UNIFORM"},AVERAGE:{name:"AVERAGE"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={OUTPUT:{name:"OUTPUT"},INPUT:{name:"INPUT"},SELF:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t=o(10),e={ADD_NODE:{name:"ADD_NODE"},SUB_NODE:{name:"SUB_NODE",keep_gates:!0},ADD_CONN:{name:"ADD_CONN"},SUB_CONN:{name:"REMOVE_CONN"},MOD_WEIGHT:{name:"MOD_WEIGHT",min:-1,max:1},MOD_BIAS:{name:"MOD_BIAS",min:-1,max:1},MOD_ACTIVATION:{name:"MOD_ACTIVATION",mutateOutput:!0,allowed:[t.LOGISTIC,t.TANH,t.RELU,t.IDENTITY,t.STEP,t.SOFTSIGN,t.SINUSOID,t.GAUSSIAN,t.BENT_IDENTITY,t.BIPOLAR,t.BIPOLAR_SIGMOID,t.HARD_TANH,t.ABSOLUTE]},ADD_SELF_CONN:{name:"ADD_SELF_CONN"},SUB_SELF_CONN:{name:"SUB_SELF_CONN"},ADD_GATE:{name:"ADD_GATE"},SUB_GATE:{name:"SUB_GATE"},ADD_BACK_CONN:{name:"ADD_BACK_CONN"},SUB_BACK_CONN:{name:"SUB_BACK_CONN"},SWAP_NODES:{name:"SWAP_NODES"}};e.ALL=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION,e.ADD_GATE,e.SUB_GATE,e.ADD_SELF_CONN,e.SUB_SELF_CONN,e.ADD_BACK_CONN,e.SUB_BACK_CONN],e.FFW=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION],n&&(n.exports=e)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FITNESS_PROPORTIONATE:{name:"FITNESS_PROPORTIONATE"},POWER:{name:"POWER",power:4},TOURNAMENT:{name:"TOURNAMENT",size:5,probability:.5}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){var e,i,s={Node:o(2),Neat:o(9),Network:o(7),Methods:o(1),Architect:o(8),Group:o(5),Connection:o(4),Config:o(3),Layer:o(6)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.neataptic;s.ninja=function(){return window.neataptic=n,s}}(),window.neataptic=s)}])}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.14/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.14/neataptic.js deleted file mode 100644 index a5f37d4..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.14/neataptic.js +++ /dev/null @@ -1,3460 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - this.derivative = 0; - this.bias = 0; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var connection in this.connections.in){ - connection = this.connections.in[connection]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(node.connections.self.gater == this ? node.old : 0); - influences[influences.length - 1] += conn.weight * conn.from.activation; - } - } - - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var i = 0; i < nodes.length; i++){ - var node = nodes[i]; - var influence = influences[i]; - - var index = connection.xtrace.nodes.indexOf(node); - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - - // Update the gains of the gates - for(var connection in this.connections.gated){ - this.connections.gated[connection].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - // Error accumulator - var error = 0; - - momentum = momentum || 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for (var connection in this.connections.out) { - var connection = this.connections.out[connection]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Learning rate - rate = rate || .3; - - // Adjust all the node's incoming connections - for (var connection in this.connections.in) { - var connection = this.connections.in[connection]; - - var gradient = this.error.projected * connection.elegibility; - - for(var i = 0; i < connection.xtrace.nodes.length; i++){ - var node = connection.xtrace.nodes[i]; - var value = connection.xtrace.values[i]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask; - - connection.weight += deltaWeight + momentum * connection.previousDeltaWeight; - - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i in this.connections.out){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var connection in connections){ - connection = connections[connection]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(conn in this.connections.out){ - conn = this.connections.out[conn]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(conn in this.connections.in){ - conn = this.connections.in[conn]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - this.connect(this.nodes[i], this.nodes[j]); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(node in this.nodes){ - if(this.nodes[node].type == 'input'){ - this.nodes[node].activate(input[node]); - } else if (this.nodes[node].type == 'output'){ - var activation = this.nodes[node].activate(); - output.push(activation); - } else { - if(training) this.nodes[node].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[node].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - this.nodes.reverse(); - target.reverse(); - - // Propagate nodes from end to start - for(node in this.nodes){ - switch(this.nodes[node].type){ - case('hidden'): - this.nodes[node].propagate(rate, momentum); - break; - case('output'): - this.nodes[node].propagate(rate, momentum, target[node]); - break; - } - } - - target.reverse(); - this.nodes.reverse(); - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to){ - var connections = from.connect(to); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var train in set) { - var input = set[train].input; - var target = set[train].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var test in set) { - input = set[test].input; - target = set[test].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var node in this.nodes){ - this.nodes[node].bias = values.bias || this.nodes[node].bias; - this.nodes[node].squash = values.squash || this.nodes[node].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: error, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - 1 - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network of both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - if(i < network1.nodes.length && i < network2.nodes.length){ - var node = null; - if(i >= size-network1.output){ - while(node == null || node.type != 'output'){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } else { - while(node == null || (i < size-network1.output && node.type == 'output')){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } - - offspring.nodes.push(node); - } else if(i < network1.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network1.nodes[network1.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network1.nodes[i]); - } - } else if(i < network2.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network2.nodes[network2.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network2.nodes[i]); - } - } - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - if(data.to == network1.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - if(data.to == network2.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(item in list){ - if(list[item] instanceof Group){ - for(var node in list[item].nodes){ - nodes.push(list[item].nodes[node]); - } - } else if(list[item] instanceof Layer){ - for(var group in list[item].nodes){ - for(var node in list[item].nodes[group].nodes){ - nodes.push(list[item].nodes[group].nodes[node]); - } - } - } else if(list[item] instanceof Node){ - nodes.push(list[item]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var node in nodes){ - for(var conn in nodes[node].connections.out){ - network.connections.push(nodes[node].connections.out[conn]); - } - for(var conn in nodes[node].connections.gated){ - network.gates.push(nodes[node].connections.gated[conn]); - } - if(nodes[node].connections.self.weight != 0){ - network.selfconns.push(nodes[node].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Return the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || [Methods.Mutation.ADD_CONN, - Methods.Mutation.SUB_CONN, - Methods.Mutation.ADD_NODE, - Methods.Mutation.SUB_NODE, - Methods.Mutation.MOD_BIAS, - Methods.Mutation.MOD_WEIGHT, - Methods.Mutation.MOD_ACTIVATION]; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - parent1 = this.getParent(); - parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2, crossoverMethod); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - if (!derivate) - return 1 / (1 + Math.exp(-x)); - var fx = Activation.LOGISTIC(x); - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if (derivate) - return 1 - Math.pow(Activation.TANH(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i in output){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i in output){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.14/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.14/neataptic.min.js deleted file mode 100644 index 920fe39..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.14/neataptic.min.js +++ /dev/null @@ -1,25 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=18)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.derivative=0,this.bias=0,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t in this.connections.in)t=this.connections.in[t],this.state+=t.from.activation*t.weight*t.gain;this.activation=this.squash(this.state)*this.mask,this.derivative=this.squash(this.state,!0);var o=[],e=[];for(var i in this.connections.gated){i=this.connections.gated[i];var s=i.to,r=o.indexOf(s);r>-1?e[r]+=i.weight*i.from.activation:(o.push(s),e.push(s.connections.self.gater==this?s.old:0),e[e.length-1]+=i.weight*i.from.activation)}for(var t in this.connections.in){t=this.connections.in[t],t.elegibility=this.connections.self.gain*this.connections.self.weight*t.elegibility+t.from.activation*t.gain;for(var a=0;a-1?t.xtrace.values[r]=s.connections.self.gain*s.connections.self.weight*t.xtrace.values[r]+this.derivative*t.elegibility*c:(t.xtrace.nodes.push(s),t.xtrace.values.push(this.derivative*t.elegibility*c))}}for(var t in this.connections.gated)this.connections.gated[t].gain=this.activation;return this.activation},propagate:function(n,t,o){var e=0;if(t=t||0,"output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i in this.connections.out){var i=this.connections.out[i],s=i.to;e+=s.error.responsibility*i.weight*i.gain}this.error.projected=this.derivative*e,e=0;for(var r in this.connections.gated){r=this.connections.gated[r];var s=r.to,a=s.connections.self.gater==this?s.old:0;a+=r.weight*r.from.activation,e+=s.error.responsibility*a}this.error.gated=this.derivative*e,this.error.responsibility=this.error.projected+this.error.gated}if("constant"!=this.type){n=n||.3;for(var i in this.connections.in){for(var i=this.connections.in[i],c=this.error.projected*i.elegibility,h=0;h=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n in this.connections.in)n=this.connections.in[n],n.elegibility=0,n.xtrace={nodes:[],values:[]};this.error.responsibility=this.error.projected=this.error.gated=0,this.old=this.state=this.activation=0},mutate:function(n){if(void 0===n)throw new Error("No mutate method given!");if(!n.name in i.Mutation)throw new Error("This method does not exist!");switch(n){case c.MOD_ACTIVATION:var t=n.allowed[(n.allowed.indexOf(this.squash)+Math.floor(Math.random()*(n.allowed.length-1))+1)%n.allowed.length];this.squash=t;break;case c.MOD_BIAS:var o=Math.random()*(n.max-n.min)+n.min;this.bias+=o}},isProjectingTo:function(n){for(conn in this.connections.out)if(conn=this.connections.out[conn],conn.to==n)return!0;return!1},isProjectedBy:function(n){for(conn in this.connections.in)if(conn=this.connections.in[conn],conn.from==n)return!0;return!1},toJSON:function(){return{bias:this.bias,type:this.type,squash:this.squash.name,mask:this.mask}}},t.fromJSON=function(n){var o=new t;o.bias=n.bias,o.type=n.type,o.mask=n.mask;for(squash in a)if(a[squash].name==n.squash){o.squash=a[squash];break}return o}}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={warnings:!0};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n,t,o){this.from=n,this.to=t,this.gain=1,this.weight=void 0===o?.2*Math.random()-.1:o,this.gater=null,this.elegibility=0,this.previousDeltaWeight=0,this.xtrace={nodes:[],values:[]}}n&&(n.exports=t),t.prototype={toJSON:function(){return{weight:this.weight}}},t.innovationID=function(n,t){return.5*(n+t)*(n+t+1)+t}}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n){this.nodes=[],this.connections={in:[],out:[],self:[]};for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var d=Math.floor(Math.random()*c.length),f=c[d];this.gate(l,c[d]),c.splice(d,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],d=0;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(n.max-n.min)+n.min;t.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],d=this.input;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),p=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),g=this.nodes[f],L=p.bias,M=p.squash;p.bias=g.bias,p.squash=g.squash,g.bias=L,g.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,d=t.dropout||0,p=t.momentum||0,v=t.ratePolicy||s.Rate.FIXED(),g=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=d,f)var m=t.crossValidate.testSize,O=t.crossValidate.testError,w=Math.ceil((1-m)*n.length),_=n.slice(0,w),A=n.slice(w);for(var N=c,T=0,L=1;L>i&&(0==u||Tg&&(g=v,m=O),u&&p.generation%u==0&&console.log("generation",p.generation,"error",O.score,"cost error",v),l&&iteration%l.iterations==0&&l.function()}f&&m.clear();var w={error:v,generations:p.generation,time:Date.now()-d};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=n.nodes.length-1-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=0;l=f-n.output)for(;null==d||"output"!=d.type;)d=Math.random()>=.5?n.nodes[l]:o.nodes[l];else for(;null==d||l=.5?n.nodes[l]:o.nodes[l];r.nodes.push(d)}else l=f-n.output?r.nodes.push(n.nodes[n.nodes.length-(l-(f-n.output-1))]):r.nodes.push(n.nodes[l]):l=f-n.output?r.nodes.push(o.nodes[o.nodes.length-(l-(f-n.output-1))]):r.nodes.push(o.nodes[l]));for(d in r.nodes)r.nodes[d]=e.fromJSON(r.nodes[d].toJSON());var p={},v={},g=n.connections.concat(n.selfconns);for(m in g){var m=g[m],O={weight:m.weight,from:n.nodes.indexOf(m.from),to:n.nodes.indexOf(m.to),gater:n.nodes.indexOf(m.gater)};if(O.to==n.nodes.length-1){if(!(O.from=.5?A[m][0]:A[m][1];N.push(m)}if(a==c){for(m in p)N.push(p[m]);for(m in v)N.push(v[m])}else if(a>c)for(m in p)N.push(p[m]);else for(m in v)N.push(v[m]);for(m in N){var T=N[m];if(T.to=0;f--)"output"==e[f].type||e[f].connections.out.length+e[f].connections.gated.length==0?(e[f].type="output",o.output++,u.push(e[f]),e.splice(f,1)):"input"!=e[f].type&&e[f].connections.in.length||(e[f].type="input",o.input++,h.push(e[f]),e.splice(f,1));if(e=h.concat(e).concat(u),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a in e){for(var l in e[a].connections.out)o.connections.push(e[a].connections.out[l]);for(var l in e[a].connections.gated)o.gates.push(e[a].connections.gated[l]);0!=e[a].connections.self.weight&&o.selfconns.push(e[a].connections.self)}return o.nodes=e,o},Perceptron:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=[];t.push(new s(n[0]));for(var o=1;o0){var O=r.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=v.connect(v,e.Connection.ALL_TO_ELSE);d.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(d,e.Connection.ALL_TO_ALL),o.connect(p,e.Connection.ALL_TO_ALL),o.connect(g,e.Connection.ALL_TO_ALL)),h.push(d),h.push(p),h.push(v),h.push(g),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){var o=0;for(var e in t)o-=n[e]*Math.log(Math.max(t[e],1e-15))+(1-n[e])*Math.log(1-Math.max(t[e],1e-15));return o},MSE:function(n,t){var o=0;for(var e in t)o+=Math.pow(n[e]-t[e],2);return o/t.length},BINARY:function(n,t){var o=0;for(var e in t)o+=Math.round(2*n[e])!=Math.round(2*t[e]);return o},MAE:function(n,t){var o=0;for(var e in t)o+=Math.abs(n[e]-t[e]);return o/t.length},MAPE:function(n,t){var o=0;for(var e in t)o+=Math.abs((t[e]-n[e])/Math.max(n[e],1e-15));return o/t.length},MSLE:function(n,t){var o=0;for(var e in t)o+=Math.log(Math.max(n[e],1e-15))-Math.log(Math.max(t[e],1e-15));return o},HINGE:function(n,t){var o=0;for(var e in t)o+=Math.max(0,1-n[e]*t[e]);return o}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={SINGLE_POINT:{name:"SINGLE_POINT",config:[.4]},TWO_POINT:{name:"TWO_POINT",config:[.4,.9]},UNIFORM:{name:"UNIFORM"},AVERAGE:{name:"AVERAGE"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={OUTPUT:{name:"OUTPUT"},INPUT:{name:"INPUT"},SELF:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t=o(10),e={ADD_NODE:{name:"ADD_NODE"},SUB_NODE:{name:"SUB_NODE",keep_gates:!0},ADD_CONN:{name:"ADD_CONN"},SUB_CONN:{name:"REMOVE_CONN"},MOD_WEIGHT:{name:"MOD_WEIGHT",min:-1,max:1},MOD_BIAS:{name:"MOD_BIAS",min:-1,max:1},MOD_ACTIVATION:{name:"MOD_ACTIVATION",mutateOutput:!0,allowed:[t.LOGISTIC,t.TANH,t.RELU,t.IDENTITY,t.STEP,t.SOFTSIGN,t.SINUSOID,t.GAUSSIAN,t.BENT_IDENTITY,t.BIPOLAR,t.BIPOLAR_SIGMOID,t.HARD_TANH,t.ABSOLUTE]},ADD_SELF_CONN:{name:"ADD_SELF_CONN"},SUB_SELF_CONN:{name:"SUB_SELF_CONN"},ADD_GATE:{name:"ADD_GATE"},SUB_GATE:{name:"SUB_GATE"},ADD_BACK_CONN:{name:"ADD_BACK_CONN"},SUB_BACK_CONN:{name:"SUB_BACK_CONN"},SWAP_NODES:{name:"SWAP_NODES"}};e.ALL=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION,e.ADD_GATE,e.SUB_GATE,e.ADD_SELF_CONN,e.SUB_SELF_CONN,e.ADD_BACK_CONN,e.SUB_BACK_CONN],e.FFW=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION],n&&(n.exports=e)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FIXED:function(){return function(n,t){return n}},STEP:function(n,t){return n=n||.9,t=t||100,function(o,e){return o*Math.pow(n,Math.floor(e/t))}},EXP:function(n){return n=n||.999,function(t,o){return t*Math.pow(n,o)}},INV:function(n,t){return n=n||.001,t=t||2,function(o,e){return o*Math.pow(1+n*e,-t)}}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FITNESS_PROPORTIONATE:{name:"FITNESS_PROPORTIONATE"},POWER:{name:"POWER",power:4},TOURNAMENT:{name:"TOURNAMENT",size:5,probability:.5}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){var e,i,s={Node:o(2),Neat:o(9),Network:o(7),Methods:o(1),Architect:o(8),Group:o(5),Connection:o(4),Config:o(3),Layer:o(6)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.neataptic;s.ninja=function(){return window.neataptic=n,s}}(),window.neataptic=s)}])}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.15/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.15/neataptic.js deleted file mode 100644 index 2f024ad..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.15/neataptic.js +++ /dev/null @@ -1,3460 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - this.derivative = 0; - this.bias = 0; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var connection in this.connections.in){ - connection = this.connections.in[connection]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(node.connections.self.gater == this ? node.old : 0); - influences[influences.length - 1] += conn.weight * conn.from.activation; - } - } - - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var i = 0; i < nodes.length; i++){ - var node = nodes[i]; - var influence = influences[i]; - - var index = connection.xtrace.nodes.indexOf(node); - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - - // Update the gains of the gates - for(var connection in this.connections.gated){ - this.connections.gated[connection].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - // Error accumulator - var error = 0; - - momentum = momentum || 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for (var connection in this.connections.out) { - var connection = this.connections.out[connection]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Learning rate - rate = rate || .3; - - // Adjust all the node's incoming connections - for (var connection in this.connections.in) { - var connection = this.connections.in[connection]; - - var gradient = this.error.projected * connection.elegibility; - - for(var i = 0; i < connection.xtrace.nodes.length; i++){ - var node = connection.xtrace.nodes[i]; - var value = connection.xtrace.values[i]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - - connection.weight += deltaWeight; - - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i in this.connections.out){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var connection in connections){ - connection = connections[connection]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(conn in this.connections.out){ - conn = this.connections.out[conn]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(conn in this.connections.in){ - conn = this.connections.in[conn]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - this.connect(this.nodes[i], this.nodes[j]); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(node in this.nodes){ - if(this.nodes[node].type == 'input'){ - this.nodes[node].activate(input[node]); - } else if (this.nodes[node].type == 'output'){ - var activation = this.nodes[node].activate(); - output.push(activation); - } else { - if(training) this.nodes[node].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[node].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - this.nodes.reverse(); - target.reverse(); - - // Propagate nodes from end to start - for(node in this.nodes){ - switch(this.nodes[node].type){ - case('hidden'): - this.nodes[node].propagate(rate, momentum); - break; - case('output'): - this.nodes[node].propagate(rate, momentum, target[node]); - break; - } - } - - target.reverse(); - this.nodes.reverse(); - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to){ - var connections = from.connect(to); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var train in set) { - var input = set[train].input; - var target = set[train].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var test in set) { - input = set[test].input; - target = set[test].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var node in this.nodes){ - this.nodes[node].bias = values.bias || this.nodes[node].bias; - this.nodes[node].squash = values.squash || this.nodes[node].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: error, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - 1 - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network of both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - if(i < network1.nodes.length && i < network2.nodes.length){ - var node = null; - if(i >= size-network1.output){ - while(node == null || node.type != 'output'){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } else { - while(node == null || (i < size-network1.output && node.type == 'output')){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } - - offspring.nodes.push(node); - } else if(i < network1.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network1.nodes[network1.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network1.nodes[i]); - } - } else if(i < network2.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network2.nodes[network2.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network2.nodes[i]); - } - } - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - if(data.to == network1.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - if(data.to == network2.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(item in list){ - if(list[item] instanceof Group){ - for(var node in list[item].nodes){ - nodes.push(list[item].nodes[node]); - } - } else if(list[item] instanceof Layer){ - for(var group in list[item].nodes){ - for(var node in list[item].nodes[group].nodes){ - nodes.push(list[item].nodes[group].nodes[node]); - } - } - } else if(list[item] instanceof Node){ - nodes.push(list[item]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var node in nodes){ - for(var conn in nodes[node].connections.out){ - network.connections.push(nodes[node].connections.out[conn]); - } - for(var conn in nodes[node].connections.gated){ - network.gates.push(nodes[node].connections.gated[conn]); - } - if(nodes[node].connections.self.weight != 0){ - network.selfconns.push(nodes[node].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Return the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || [Methods.Mutation.ADD_CONN, - Methods.Mutation.SUB_CONN, - Methods.Mutation.ADD_NODE, - Methods.Mutation.SUB_NODE, - Methods.Mutation.MOD_BIAS, - Methods.Mutation.MOD_WEIGHT, - Methods.Mutation.MOD_ACTIVATION]; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - parent1 = this.getParent(); - parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2, crossoverMethod); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - if (!derivate) - return 1 / (1 + Math.exp(-x)); - var fx = Activation.LOGISTIC(x); - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if (derivate) - return 1 - Math.pow(Activation.TANH(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i in output){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i in output){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.15/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.15/neataptic.min.js deleted file mode 100644 index 1b873ab..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.15/neataptic.min.js +++ /dev/null @@ -1,25 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=18)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.derivative=0,this.bias=0,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t in this.connections.in)t=this.connections.in[t],this.state+=t.from.activation*t.weight*t.gain;this.activation=this.squash(this.state)*this.mask,this.derivative=this.squash(this.state,!0);var o=[],e=[];for(var i in this.connections.gated){i=this.connections.gated[i];var s=i.to,r=o.indexOf(s);r>-1?e[r]+=i.weight*i.from.activation:(o.push(s),e.push(s.connections.self.gater==this?s.old:0),e[e.length-1]+=i.weight*i.from.activation)}for(var t in this.connections.in){t=this.connections.in[t],t.elegibility=this.connections.self.gain*this.connections.self.weight*t.elegibility+t.from.activation*t.gain;for(var a=0;a-1?t.xtrace.values[r]=s.connections.self.gain*s.connections.self.weight*t.xtrace.values[r]+this.derivative*t.elegibility*c:(t.xtrace.nodes.push(s),t.xtrace.values.push(this.derivative*t.elegibility*c))}}for(var t in this.connections.gated)this.connections.gated[t].gain=this.activation;return this.activation},propagate:function(n,t,o){var e=0;if(t=t||0,"output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i in this.connections.out){var i=this.connections.out[i],s=i.to;e+=s.error.responsibility*i.weight*i.gain}this.error.projected=this.derivative*e,e=0;for(var r in this.connections.gated){r=this.connections.gated[r];var s=r.to,a=s.connections.self.gater==this?s.old:0;a+=r.weight*r.from.activation,e+=s.error.responsibility*a}this.error.gated=this.derivative*e,this.error.responsibility=this.error.projected+this.error.gated}if("constant"!=this.type){n=n||.3;for(var i in this.connections.in){for(var i=this.connections.in[i],c=this.error.projected*i.elegibility,h=0;h=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n in this.connections.in)n=this.connections.in[n],n.elegibility=0,n.xtrace={nodes:[],values:[]};this.error.responsibility=this.error.projected=this.error.gated=0,this.old=this.state=this.activation=0},mutate:function(n){if(void 0===n)throw new Error("No mutate method given!");if(!n.name in i.Mutation)throw new Error("This method does not exist!");switch(n){case c.MOD_ACTIVATION:var t=n.allowed[(n.allowed.indexOf(this.squash)+Math.floor(Math.random()*(n.allowed.length-1))+1)%n.allowed.length];this.squash=t;break;case c.MOD_BIAS:var o=Math.random()*(n.max-n.min)+n.min;this.bias+=o}},isProjectingTo:function(n){for(conn in this.connections.out)if(conn=this.connections.out[conn],conn.to==n)return!0;return!1},isProjectedBy:function(n){for(conn in this.connections.in)if(conn=this.connections.in[conn],conn.from==n)return!0;return!1},toJSON:function(){return{bias:this.bias,type:this.type,squash:this.squash.name,mask:this.mask}}},t.fromJSON=function(n){var o=new t;o.bias=n.bias,o.type=n.type,o.mask=n.mask;for(squash in a)if(a[squash].name==n.squash){o.squash=a[squash];break}return o}}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={warnings:!0};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n,t,o){this.from=n,this.to=t,this.gain=1,this.weight=void 0===o?.2*Math.random()-.1:o,this.gater=null,this.elegibility=0,this.previousDeltaWeight=0,this.xtrace={nodes:[],values:[]}}n&&(n.exports=t),t.prototype={toJSON:function(){return{weight:this.weight}}},t.innovationID=function(n,t){return.5*(n+t)*(n+t+1)+t}}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n){this.nodes=[],this.connections={in:[],out:[],self:[]};for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var d=Math.floor(Math.random()*c.length),f=c[d];this.gate(l,c[d]),c.splice(d,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],d=0;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(n.max-n.min)+n.min;t.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],d=this.input;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),p=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),g=this.nodes[f],L=p.bias,M=p.squash;p.bias=g.bias,p.squash=g.squash,g.bias=L,g.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,d=t.dropout||0,p=t.momentum||0,v=t.ratePolicy||s.Rate.FIXED(),g=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=d,f)var m=t.crossValidate.testSize,O=t.crossValidate.testError,w=Math.ceil((1-m)*n.length),_=n.slice(0,w),A=n.slice(w);for(var N=c,T=0,L=1;L>i&&(0==u||Tg&&(g=v,m=O),u&&p.generation%u==0&&console.log("generation",p.generation,"error",O.score,"cost error",v),l&&iteration%l.iterations==0&&l.function()}f&&m.clear();var w={error:v,generations:p.generation,time:Date.now()-d};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=n.nodes.length-1-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=0;l=f-n.output)for(;null==d||"output"!=d.type;)d=Math.random()>=.5?n.nodes[l]:o.nodes[l];else for(;null==d||l=.5?n.nodes[l]:o.nodes[l];r.nodes.push(d)}else l=f-n.output?r.nodes.push(n.nodes[n.nodes.length-(l-(f-n.output-1))]):r.nodes.push(n.nodes[l]):l=f-n.output?r.nodes.push(o.nodes[o.nodes.length-(l-(f-n.output-1))]):r.nodes.push(o.nodes[l]));for(d in r.nodes)r.nodes[d]=e.fromJSON(r.nodes[d].toJSON());var p={},v={},g=n.connections.concat(n.selfconns);for(m in g){var m=g[m],O={weight:m.weight,from:n.nodes.indexOf(m.from),to:n.nodes.indexOf(m.to),gater:n.nodes.indexOf(m.gater)};if(O.to==n.nodes.length-1){if(!(O.from=.5?A[m][0]:A[m][1];N.push(m)}if(a==c){for(m in p)N.push(p[m]);for(m in v)N.push(v[m])}else if(a>c)for(m in p)N.push(p[m]);else for(m in v)N.push(v[m]);for(m in N){var T=N[m];if(T.to=0;f--)"output"==e[f].type||e[f].connections.out.length+e[f].connections.gated.length==0?(e[f].type="output",o.output++,u.push(e[f]),e.splice(f,1)):"input"!=e[f].type&&e[f].connections.in.length||(e[f].type="input",o.input++,h.push(e[f]),e.splice(f,1));if(e=h.concat(e).concat(u),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a in e){for(var l in e[a].connections.out)o.connections.push(e[a].connections.out[l]);for(var l in e[a].connections.gated)o.gates.push(e[a].connections.gated[l]);0!=e[a].connections.self.weight&&o.selfconns.push(e[a].connections.self)}return o.nodes=e,o},Perceptron:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=[];t.push(new s(n[0]));for(var o=1;o0){var O=r.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=v.connect(v,e.Connection.ALL_TO_ELSE);d.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(d,e.Connection.ALL_TO_ALL),o.connect(p,e.Connection.ALL_TO_ALL),o.connect(g,e.Connection.ALL_TO_ALL)),h.push(d),h.push(p),h.push(v),h.push(g),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){var o=0;for(var e in t)o-=n[e]*Math.log(Math.max(t[e],1e-15))+(1-n[e])*Math.log(1-Math.max(t[e],1e-15));return o},MSE:function(n,t){var o=0;for(var e in t)o+=Math.pow(n[e]-t[e],2);return o/t.length},BINARY:function(n,t){var o=0;for(var e in t)o+=Math.round(2*n[e])!=Math.round(2*t[e]);return o},MAE:function(n,t){var o=0;for(var e in t)o+=Math.abs(n[e]-t[e]);return o/t.length},MAPE:function(n,t){var o=0;for(var e in t)o+=Math.abs((t[e]-n[e])/Math.max(n[e],1e-15));return o/t.length},MSLE:function(n,t){var o=0;for(var e in t)o+=Math.log(Math.max(n[e],1e-15))-Math.log(Math.max(t[e],1e-15));return o},HINGE:function(n,t){var o=0;for(var e in t)o+=Math.max(0,1-n[e]*t[e]);return o}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={SINGLE_POINT:{name:"SINGLE_POINT",config:[.4]},TWO_POINT:{name:"TWO_POINT",config:[.4,.9]},UNIFORM:{name:"UNIFORM"},AVERAGE:{name:"AVERAGE"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={OUTPUT:{name:"OUTPUT"},INPUT:{name:"INPUT"},SELF:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t=o(10),e={ADD_NODE:{name:"ADD_NODE"},SUB_NODE:{name:"SUB_NODE",keep_gates:!0},ADD_CONN:{name:"ADD_CONN"},SUB_CONN:{name:"REMOVE_CONN"},MOD_WEIGHT:{name:"MOD_WEIGHT",min:-1,max:1},MOD_BIAS:{name:"MOD_BIAS",min:-1,max:1},MOD_ACTIVATION:{name:"MOD_ACTIVATION",mutateOutput:!0,allowed:[t.LOGISTIC,t.TANH,t.RELU,t.IDENTITY,t.STEP,t.SOFTSIGN,t.SINUSOID,t.GAUSSIAN,t.BENT_IDENTITY,t.BIPOLAR,t.BIPOLAR_SIGMOID,t.HARD_TANH,t.ABSOLUTE]},ADD_SELF_CONN:{name:"ADD_SELF_CONN"},SUB_SELF_CONN:{name:"SUB_SELF_CONN"},ADD_GATE:{name:"ADD_GATE"},SUB_GATE:{name:"SUB_GATE"},ADD_BACK_CONN:{name:"ADD_BACK_CONN"},SUB_BACK_CONN:{name:"SUB_BACK_CONN"},SWAP_NODES:{name:"SWAP_NODES"}};e.ALL=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION,e.ADD_GATE,e.SUB_GATE,e.ADD_SELF_CONN,e.SUB_SELF_CONN,e.ADD_BACK_CONN,e.SUB_BACK_CONN],e.FFW=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION],n&&(n.exports=e)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FIXED:function(){return function(n,t){return n}},STEP:function(n,t){return n=n||.9,t=t||100,function(o,e){return o*Math.pow(n,Math.floor(e/t))}},EXP:function(n){return n=n||.999,function(t,o){return t*Math.pow(n,o)}},INV:function(n,t){return n=n||.001,t=t||2,function(o,e){return o*Math.pow(1+n*e,-t)}}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FITNESS_PROPORTIONATE:{name:"FITNESS_PROPORTIONATE"},POWER:{name:"POWER",power:4},TOURNAMENT:{name:"TOURNAMENT",size:5,probability:.5}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){var e,i,s={Node:o(2),Neat:o(9),Network:o(7),Methods:o(1),Architect:o(8),Group:o(5),Connection:o(4),Config:o(3),Layer:o(6)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.neataptic;s.ninja=function(){return window.neataptic=n,s}}(),window.neataptic=s)}])}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.16/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.16/neataptic.js deleted file mode 100644 index ca2daff..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.16/neataptic.js +++ /dev/null @@ -1,3460 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - this.derivative = 0; - this.bias = 0; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var connection in this.connections.in){ - connection = this.connections.in[connection]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(node.connections.self.gater == this ? node.old : 0); - influences[influences.length - 1] += conn.weight * conn.from.activation; - } - } - - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var i = 0; i < nodes.length; i++){ - var node = nodes[i]; - var influence = influences[i]; - - var index = connection.xtrace.nodes.indexOf(node); - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - - // Update the gains of the gates - for(var connection in this.connections.gated){ - this.connections.gated[connection].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - // Error accumulator - var error = 0; - - momentum = momentum || 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for (var connection in this.connections.out) { - var connection = this.connections.out[connection]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Learning rate - rate = rate || .3; - - // Adjust all the node's incoming connections - for (var connection in this.connections.in) { - var connection = this.connections.in[connection]; - - var gradient = this.error.projected * connection.elegibility; - - for(var i = 0; i < connection.xtrace.nodes.length; i++){ - var node = connection.xtrace.nodes[i]; - var value = connection.xtrace.values[i]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - - connection.weight += deltaWeight; - - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i in this.connections.out){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var connection in connections){ - connection = connections[connection]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(conn in this.connections.out){ - conn = this.connections.out[conn]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(conn in this.connections.in){ - conn = this.connections.in[conn]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - this.connect(this.nodes[i], this.nodes[j]); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(node in this.nodes){ - if(this.nodes[node].type == 'input'){ - this.nodes[node].activate(input[node]); - } else if (this.nodes[node].type == 'output'){ - var activation = this.nodes[node].activate(); - output.push(activation); - } else { - if(training) this.nodes[node].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[node].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= 0; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to){ - var connections = from.connect(to); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var train in set) { - var input = set[train].input; - var target = set[train].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var test in set) { - input = set[test].input; - target = set[test].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var node in this.nodes){ - this.nodes[node].bias = values.bias || this.nodes[node].bias; - this.nodes[node].squash = values.squash || this.nodes[node].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: error, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - 1 - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network of both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - if(i < network1.nodes.length && i < network2.nodes.length){ - var node = null; - if(i >= size-network1.output){ - while(node == null || node.type != 'output'){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } else { - while(node == null || (i < size-network1.output && node.type == 'output')){ - if(Math.random() >= 0.5){ - node = network1.nodes[i]; - } else { - node = network2.nodes[i]; - } - } - } - - offspring.nodes.push(node); - } else if(i < network1.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network1.nodes[network1.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network1.nodes[i]); - } - } else if(i < network2.nodes.length){ - if(i >= size-network1.output){ - offspring.nodes.push(network2.nodes[network2.nodes.length - (i - (size-network1.output - 1))]); - } else { - offspring.nodes.push(network2.nodes[i]); - } - } - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - if(data.to == network1.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - if(data.to == network2.nodes.length - 1){ - if(data.from < size - 1){ - data.to = size - 1; - } else { - continue; - } - } - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(item in list){ - if(list[item] instanceof Group){ - for(var node in list[item].nodes){ - nodes.push(list[item].nodes[node]); - } - } else if(list[item] instanceof Layer){ - for(var group in list[item].nodes){ - for(var node in list[item].nodes[group].nodes){ - nodes.push(list[item].nodes[group].nodes[node]); - } - } - } else if(list[item] instanceof Node){ - nodes.push(list[item]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var node in nodes){ - for(var conn in nodes[node].connections.out){ - network.connections.push(nodes[node].connections.out[conn]); - } - for(var conn in nodes[node].connections.gated){ - network.gates.push(nodes[node].connections.gated[conn]); - } - if(nodes[node].connections.self.weight != 0){ - network.selfconns.push(nodes[node].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Return the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || [Methods.Mutation.ADD_CONN, - Methods.Mutation.SUB_CONN, - Methods.Mutation.ADD_NODE, - Methods.Mutation.SUB_NODE, - Methods.Mutation.MOD_BIAS, - Methods.Mutation.MOD_WEIGHT, - Methods.Mutation.MOD_ACTIVATION]; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - parent1 = this.getParent(); - parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2, crossoverMethod); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - if (!derivate) - return 1 / (1 + Math.exp(-x)); - var fx = Activation.LOGISTIC(x); - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if (derivate) - return 1 - Math.pow(Activation.TANH(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i in output){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i in output){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.16/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.16/neataptic.min.js deleted file mode 100644 index d0c1778..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.16/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=18)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.derivative=0,this.bias=0,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t in this.connections.in)t=this.connections.in[t],this.state+=t.from.activation*t.weight*t.gain;this.activation=this.squash(this.state)*this.mask,this.derivative=this.squash(this.state,!0);var o=[],e=[];for(var i in this.connections.gated){i=this.connections.gated[i];var s=i.to,r=o.indexOf(s);r>-1?e[r]+=i.weight*i.from.activation:(o.push(s),e.push(s.connections.self.gater==this?s.old:0),e[e.length-1]+=i.weight*i.from.activation)}for(var t in this.connections.in){t=this.connections.in[t],t.elegibility=this.connections.self.gain*this.connections.self.weight*t.elegibility+t.from.activation*t.gain;for(var a=0;a-1?t.xtrace.values[r]=s.connections.self.gain*s.connections.self.weight*t.xtrace.values[r]+this.derivative*t.elegibility*c:(t.xtrace.nodes.push(s),t.xtrace.values.push(this.derivative*t.elegibility*c))}}for(var t in this.connections.gated)this.connections.gated[t].gain=this.activation;return this.activation},propagate:function(n,t,o){var e=0;if(t=t||0,"output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i in this.connections.out){var i=this.connections.out[i],s=i.to;e+=s.error.responsibility*i.weight*i.gain}this.error.projected=this.derivative*e,e=0;for(var r in this.connections.gated){r=this.connections.gated[r];var s=r.to,a=s.connections.self.gater==this?s.old:0;a+=r.weight*r.from.activation,e+=s.error.responsibility*a}this.error.gated=this.derivative*e,this.error.responsibility=this.error.projected+this.error.gated}if("constant"!=this.type){n=n||.3;for(var i in this.connections.in){for(var i=this.connections.in[i],c=this.error.projected*i.elegibility,h=0;h=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n in this.connections.in)n=this.connections.in[n],n.elegibility=0,n.xtrace={nodes:[],values:[]};this.error.responsibility=this.error.projected=this.error.gated=0,this.old=this.state=this.activation=0},mutate:function(n){if(void 0===n)throw new Error("No mutate method given!");if(!n.name in i.Mutation)throw new Error("This method does not exist!");switch(n){case c.MOD_ACTIVATION:var t=n.allowed[(n.allowed.indexOf(this.squash)+Math.floor(Math.random()*(n.allowed.length-1))+1)%n.allowed.length];this.squash=t;break;case c.MOD_BIAS:var o=Math.random()*(n.max-n.min)+n.min;this.bias+=o}},isProjectingTo:function(n){for(conn in this.connections.out)if(conn=this.connections.out[conn],conn.to==n)return!0;return!1},isProjectedBy:function(n){for(conn in this.connections.in)if(conn=this.connections.in[conn],conn.from==n)return!0;return!1},toJSON:function(){return{bias:this.bias,type:this.type,squash:this.squash.name,mask:this.mask}}},t.fromJSON=function(n){var o=new t;o.bias=n.bias,o.type=n.type,o.mask=n.mask;for(squash in a)if(a[squash].name==n.squash){o.squash=a[squash];break}return o}}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={warnings:!0};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n,t,o){this.from=n,this.to=t,this.gain=1,this.weight=void 0===o?.2*Math.random()-.1:o,this.gater=null,this.elegibility=0,this.previousDeltaWeight=0,this.xtrace={nodes:[],values:[]}}n&&(n.exports=t),t.prototype={toJSON:function(){return{weight:this.weight}}},t.innovationID=function(n,t){return.5*(n+t)*(n+t+1)+t}}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n){this.nodes=[],this.connections={in:[],out:[],self:[]};for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=this.nodes.length-this.output;i--)this.nodes[i].propagate(n,t,o[--e]);for(var i=this.nodes.length-this.output-1;i>=0;i--)this.nodes[i].propagate(n,t)},clear:function(){for(var n in this.nodes)this.nodes[n].clear()},connect:function(n,t){var o=n.connect(t);for(var e in o)e=o[e],n!=t?this.connections.push(e):this.selfconns.push(e);return o},disconnect:function(n,t){var o=n==t?this.selfconns:this.connections;for(conn in o){var e=o[conn];if(e.from==n&&e.to==t){null!=e.gater&&this.ungate(e),o.splice(conn,1);break}}n.disconnect(t)},gate:function(n,t){if(-1==this.nodes.indexOf(n))throw new Error("This node is not part of the network!");if(null!=t.gater)return void(r.warnings&&console.warn("This connection is already gated!"));n.gate(t),this.gates.push(t)},ungate:function(n){var t=this.gates.indexOf(n);if(-1==t)throw new Error("This connection is not gated!");this.gates.splice(t,1),n.gater.ungate(n)},remove:function(n){var t=this.nodes.indexOf(n);if(-1==t)throw new Error("This node does not exist in the network!");for(var o=[],e=[],i=n.connections.in.length-1;i>=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var p=Math.floor(Math.random()*c.length),f=c[p];this.gate(l,c[p]),c.splice(p,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],p=0;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(n.max-n.min)+n.min;t.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),g=this.nodes[f],L=d.bias,M=d.squash;d.bias=g.bias,d.squash=g.squash,g.bias=L,g.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,p=t.dropout||0,d=t.momentum||0,v=t.ratePolicy||s.Rate.FIXED(),g=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=p,f)var m=t.crossValidate.testSize,O=t.crossValidate.testError,w=Math.ceil((1-m)*n.length),_=n.slice(0,w),A=n.slice(w);for(var N=c,T=0,L=1;L>i&&(0==u||Tg&&(g=v,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",v),l&&iteration%l.iterations==0&&l.function()}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=n.nodes.length-1-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=0;l=f-n.output)for(;null==p||"output"!=p.type;)p=Math.random()>=.5?n.nodes[l]:o.nodes[l];else for(;null==p||l=.5?n.nodes[l]:o.nodes[l];r.nodes.push(p)}else l=f-n.output?r.nodes.push(n.nodes[n.nodes.length-(l-(f-n.output-1))]):r.nodes.push(n.nodes[l]):l=f-n.output?r.nodes.push(o.nodes[o.nodes.length-(l-(f-n.output-1))]):r.nodes.push(o.nodes[l]));for(p in r.nodes)r.nodes[p]=e.fromJSON(r.nodes[p].toJSON());var d={},v={},g=n.connections.concat(n.selfconns);for(m in g){var m=g[m],O={weight:m.weight,from:n.nodes.indexOf(m.from),to:n.nodes.indexOf(m.to),gater:n.nodes.indexOf(m.gater)};if(O.to==n.nodes.length-1){if(!(O.from=.5?A[m][0]:A[m][1];N.push(m)}if(a==c){for(m in d)N.push(d[m]);for(m in v)N.push(v[m])}else if(a>c)for(m in d)N.push(d[m]);else for(m in v)N.push(v[m]);for(m in N){var T=N[m];if(T.to=0;f--)"output"==e[f].type||e[f].connections.out.length+e[f].connections.gated.length==0?(e[f].type="output",o.output++,u.push(e[f]),e.splice(f,1)):"input"!=e[f].type&&e[f].connections.in.length||(e[f].type="input",o.input++,h.push(e[f]),e.splice(f,1));if(e=h.concat(e).concat(u),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a in e){for(var l in e[a].connections.out)o.connections.push(e[a].connections.out[l]);for(var l in e[a].connections.gated)o.gates.push(e[a].connections.gated[l]);0!=e[a].connections.self.weight&&o.selfconns.push(e[a].connections.self)}return o.nodes=e,o},Perceptron:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=[];t.push(new s(n[0]));for(var o=1;o0){var O=r.connect(v,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=v.connect(v,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(v,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(g,e.Connection.ALL_TO_ALL)),h.push(p),h.push(d),h.push(v),h.push(g),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){var o=0;for(var e in t)o-=n[e]*Math.log(Math.max(t[e],1e-15))+(1-n[e])*Math.log(1-Math.max(t[e],1e-15));return o},MSE:function(n,t){var o=0;for(var e in t)o+=Math.pow(n[e]-t[e],2);return o/t.length},BINARY:function(n,t){var o=0;for(var e in t)o+=Math.round(2*n[e])!=Math.round(2*t[e]);return o},MAE:function(n,t){var o=0;for(var e in t)o+=Math.abs(n[e]-t[e]);return o/t.length},MAPE:function(n,t){var o=0;for(var e in t)o+=Math.abs((t[e]-n[e])/Math.max(n[e],1e-15));return o/t.length},MSLE:function(n,t){var o=0;for(var e in t)o+=Math.log(Math.max(n[e],1e-15))-Math.log(Math.max(t[e],1e-15));return o},HINGE:function(n,t){var o=0;for(var e in t)o+=Math.max(0,1-n[e]*t[e]);return o}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={SINGLE_POINT:{name:"SINGLE_POINT",config:[.4]},TWO_POINT:{name:"TWO_POINT",config:[.4,.9]},UNIFORM:{name:"UNIFORM"},AVERAGE:{name:"AVERAGE"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={OUTPUT:{name:"OUTPUT"},INPUT:{name:"INPUT"},SELF:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t=o(10),e={ADD_NODE:{name:"ADD_NODE"},SUB_NODE:{name:"SUB_NODE",keep_gates:!0},ADD_CONN:{name:"ADD_CONN"},SUB_CONN:{name:"REMOVE_CONN"},MOD_WEIGHT:{name:"MOD_WEIGHT",min:-1,max:1},MOD_BIAS:{name:"MOD_BIAS",min:-1,max:1},MOD_ACTIVATION:{name:"MOD_ACTIVATION",mutateOutput:!0,allowed:[t.LOGISTIC,t.TANH,t.RELU,t.IDENTITY,t.STEP,t.SOFTSIGN,t.SINUSOID,t.GAUSSIAN,t.BENT_IDENTITY,t.BIPOLAR,t.BIPOLAR_SIGMOID,t.HARD_TANH,t.ABSOLUTE]},ADD_SELF_CONN:{name:"ADD_SELF_CONN"},SUB_SELF_CONN:{name:"SUB_SELF_CONN"},ADD_GATE:{name:"ADD_GATE"},SUB_GATE:{name:"SUB_GATE"},ADD_BACK_CONN:{name:"ADD_BACK_CONN"},SUB_BACK_CONN:{name:"SUB_BACK_CONN"},SWAP_NODES:{name:"SWAP_NODES"}};e.ALL=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION,e.ADD_GATE,e.SUB_GATE,e.ADD_SELF_CONN,e.SUB_SELF_CONN,e.ADD_BACK_CONN,e.SUB_BACK_CONN],e.FFW=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION],n&&(n.exports=e)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FIXED:function(){return function(n,t){return n}},STEP:function(n,t){return n=n||.9,t=t||100,function(o,e){return o*Math.pow(n,Math.floor(e/t))}},EXP:function(n){return n=n||.999,function(t,o){return t*Math.pow(n,o)}},INV:function(n,t){return n=n||.001,t=t||2,function(o,e){return o*Math.pow(1+n*e,-t)}}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FITNESS_PROPORTIONATE:{name:"FITNESS_PROPORTIONATE"},POWER:{name:"POWER",power:4},TOURNAMENT:{name:"TOURNAMENT",size:5,probability:.5}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){var e,i,s={Node:o(2),Neat:o(9),Network:o(7),Methods:o(1),Architect:o(8),Group:o(5),Connection:o(4),Config:o(3),Layer:o(6)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.neataptic;s.ninja=function(){return window.neataptic=n,s}}(),window.neataptic=s)}])}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.17/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.17/neataptic.js deleted file mode 100644 index 8cd3e00..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.17/neataptic.js +++ /dev/null @@ -1,3433 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - this.derivative = 0; - this.bias = 0; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var connection in this.connections.in){ - connection = this.connections.in[connection]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(node.connections.self.gater == this ? node.old : 0); - influences[influences.length - 1] += conn.weight * conn.from.activation; - } - } - - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var i = 0; i < nodes.length; i++){ - var node = nodes[i]; - var influence = influences[i]; - - var index = connection.xtrace.nodes.indexOf(node); - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - - // Update the gains of the gates - for(var connection in this.connections.gated){ - this.connections.gated[connection].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - // Error accumulator - var error = 0; - - momentum = momentum || 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for (var connection in this.connections.out) { - var connection = this.connections.out[connection]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Learning rate - rate = rate || .3; - - // Adjust all the node's incoming connections - for (var connection in this.connections.in) { - var connection = this.connections.in[connection]; - - var gradient = this.error.projected * connection.elegibility; - - for(var i = 0; i < connection.xtrace.nodes.length; i++){ - var node = connection.xtrace.nodes[i]; - var value = connection.xtrace.values[i]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - - connection.weight += deltaWeight; - - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i in this.connections.out){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var connection in connections){ - connection = connections[connection]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(conn in this.connections.out){ - conn = this.connections.out[conn]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(conn in this.connections.in){ - conn = this.connections.in[conn]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - this.connect(this.nodes[i], this.nodes[j]); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(node in this.nodes){ - if(this.nodes[node].type == 'input'){ - this.nodes[node].activate(input[node]); - } else if (this.nodes[node].type == 'output'){ - var activation = this.nodes[node].activate(); - output.push(activation); - } else { - if(training) this.nodes[node].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[node].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= 0; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to){ - var connections = from.connect(to); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var train in set) { - var input = set[train].input; - var target = set[train].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var test in set) { - input = set[test].input; - target = set[test].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var node in this.nodes){ - this.nodes[node].bias = values.bias || this.nodes[node].bias; - this.nodes[node].squash = values.squash || this.nodes[node].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iterations }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - offspring.nodes.push(node); - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(item in list){ - if(list[item] instanceof Group){ - for(var node in list[item].nodes){ - nodes.push(list[item].nodes[node]); - } - } else if(list[item] instanceof Layer){ - for(var group in list[item].nodes){ - for(var node in list[item].nodes[group].nodes){ - nodes.push(list[item].nodes[group].nodes[node]); - } - } - } else if(list[item] instanceof Node){ - nodes.push(list[item]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var node in nodes){ - for(var conn in nodes[node].connections.out){ - network.connections.push(nodes[node].connections.out[conn]); - } - for(var conn in nodes[node].connections.gated){ - network.gates.push(nodes[node].connections.gated[conn]); - } - if(nodes[node].connections.self.weight != 0){ - network.selfconns.push(nodes[node].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Return the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - if (!derivate) - return 1 / (1 + Math.exp(-x)); - var fx = Activation.LOGISTIC(x); - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if (derivate) - return 1 - Math.pow(Activation.TANH(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i in output){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i in output){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.17/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.17/neataptic.min.js deleted file mode 100644 index 464183e..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.17/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=18)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.derivative=0,this.bias=0,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t in this.connections.in)t=this.connections.in[t],this.state+=t.from.activation*t.weight*t.gain;this.activation=this.squash(this.state)*this.mask,this.derivative=this.squash(this.state,!0);var o=[],e=[];for(var i in this.connections.gated){i=this.connections.gated[i];var s=i.to,r=o.indexOf(s);r>-1?e[r]+=i.weight*i.from.activation:(o.push(s),e.push(s.connections.self.gater==this?s.old:0),e[e.length-1]+=i.weight*i.from.activation)}for(var t in this.connections.in){t=this.connections.in[t],t.elegibility=this.connections.self.gain*this.connections.self.weight*t.elegibility+t.from.activation*t.gain;for(var a=0;a-1?t.xtrace.values[r]=s.connections.self.gain*s.connections.self.weight*t.xtrace.values[r]+this.derivative*t.elegibility*c:(t.xtrace.nodes.push(s),t.xtrace.values.push(this.derivative*t.elegibility*c))}}for(var t in this.connections.gated)this.connections.gated[t].gain=this.activation;return this.activation},propagate:function(n,t,o){var e=0;if(t=t||0,"output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i in this.connections.out){var i=this.connections.out[i],s=i.to;e+=s.error.responsibility*i.weight*i.gain}this.error.projected=this.derivative*e,e=0;for(var r in this.connections.gated){r=this.connections.gated[r];var s=r.to,a=s.connections.self.gater==this?s.old:0;a+=r.weight*r.from.activation,e+=s.error.responsibility*a}this.error.gated=this.derivative*e,this.error.responsibility=this.error.projected+this.error.gated}if("constant"!=this.type){n=n||.3;for(var i in this.connections.in){for(var i=this.connections.in[i],c=this.error.projected*i.elegibility,h=0;h=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n in this.connections.in)n=this.connections.in[n],n.elegibility=0,n.xtrace={nodes:[],values:[]};this.error.responsibility=this.error.projected=this.error.gated=0,this.old=this.state=this.activation=0},mutate:function(n){if(void 0===n)throw new Error("No mutate method given!");if(!n.name in i.Mutation)throw new Error("This method does not exist!");switch(n){case c.MOD_ACTIVATION:var t=n.allowed[(n.allowed.indexOf(this.squash)+Math.floor(Math.random()*(n.allowed.length-1))+1)%n.allowed.length];this.squash=t;break;case c.MOD_BIAS:var o=Math.random()*(n.max-n.min)+n.min;this.bias+=o}},isProjectingTo:function(n){for(conn in this.connections.out)if(conn=this.connections.out[conn],conn.to==n)return!0;return!1},isProjectedBy:function(n){for(conn in this.connections.in)if(conn=this.connections.in[conn],conn.from==n)return!0;return!1},toJSON:function(){return{bias:this.bias,type:this.type,squash:this.squash.name,mask:this.mask}}},t.fromJSON=function(n){var o=new t;o.bias=n.bias,o.type=n.type,o.mask=n.mask;for(squash in a)if(a[squash].name==n.squash){o.squash=a[squash];break}return o}}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={warnings:!0};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n,t,o){this.from=n,this.to=t,this.gain=1,this.weight=void 0===o?.2*Math.random()-.1:o,this.gater=null,this.elegibility=0,this.previousDeltaWeight=0,this.xtrace={nodes:[],values:[]}}n&&(n.exports=t),t.prototype={toJSON:function(){return{weight:this.weight}}},t.innovationID=function(n,t){return.5*(n+t)*(n+t+1)+t}}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n){this.nodes=[],this.connections={in:[],out:[],self:[]};for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=this.nodes.length-this.output;i--)this.nodes[i].propagate(n,t,o[--e]);for(var i=this.nodes.length-this.output-1;i>=0;i--)this.nodes[i].propagate(n,t)},clear:function(){for(var n in this.nodes)this.nodes[n].clear()},connect:function(n,t){var o=n.connect(t);for(var e in o)e=o[e],n!=t?this.connections.push(e):this.selfconns.push(e);return o},disconnect:function(n,t){var o=n==t?this.selfconns:this.connections;for(conn in o){var e=o[conn];if(e.from==n&&e.to==t){null!=e.gater&&this.ungate(e),o.splice(conn,1);break}}n.disconnect(t)},gate:function(n,t){if(-1==this.nodes.indexOf(n))throw new Error("This node is not part of the network!");if(null!=t.gater)return void(r.warnings&&console.warn("This connection is already gated!"));n.gate(t),this.gates.push(t)},ungate:function(n){var t=this.gates.indexOf(n);if(-1==t)throw new Error("This connection is not gated!");this.gates.splice(t,1),n.gater.ungate(n)},remove:function(n){var t=this.nodes.indexOf(n);if(-1==t)throw new Error("This node does not exist in the network!");for(var o=[],e=[],i=n.connections.in.length-1;i>=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var d=Math.floor(Math.random()*c.length),f=c[d];this.gate(l,c[d]),c.splice(d,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],d=0;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(n.max-n.min)+n.min;t.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],d=this.input;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),p=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),g=this.nodes[f],L=p.bias,M=p.squash;p.bias=g.bias,p.squash=g.squash,g.bias=L,g.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,d=t.dropout||0,p=t.momentum||0,v=t.ratePolicy||s.Rate.FIXED(),g=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=d,f)var m=t.crossValidate.testSize,O=t.crossValidate.testError,w=Math.ceil((1-m)*n.length),_=n.slice(0,w),A=n.slice(w);for(var N=c,T=0,L=1;L>i&&(0==u||Tg&&(g=v,m=O),u&&p.generation%u==0&&console.log("generation",p.generation,"error",O.score,"cost error",v),l&&iteration%l.iterations==0&&l.function({error:v,iteration:c})}f&&m.clear();var w={error:g,generations:p.generation,time:Date.now()-d};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=o.input-1;i>=0;i--)o.nodes.splice(i,1);for(var i=n.nodes.length-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=n.output,d=0;d=.5?n.nodes[d]:o.nodes[d],g=p<.5?n.nodes[d]:o.nodes[d];void 0!==v&&"output"!=v.type||(v=g)}else if(Math.random()>=.5)var v=n.nodes[n.nodes.length+d-f];else var v=o.nodes[o.nodes.length+d-f];r.nodes.push(v)}for(v in r.nodes)r.nodes[v]=e.fromJSON(r.nodes[v].toJSON());var m={},O={},w=n.connections.concat(n.selfconns);for(_ in w){var _=w[_],A={weight:_.weight,from:n.nodes.indexOf(_.from),to:n.nodes.indexOf(_.to),gater:n.nodes.indexOf(_.gater)},N=i.innovationID(A.from,A.to);m[N]=A}var T=o.connections.concat(o.selfconns);for(_ in T){var _=T[_],A={weight:_.weight,from:o.nodes.indexOf(_.from),to:o.nodes.indexOf(_.to),gater:o.nodes.indexOf(_.gater)},N=i.innovationID(A.from,A.to);O[N]=A}var L={};for(var N in m)N in O&&(L[N]=[m[N],O[N]],delete m[N],delete O[N]);var M=[];for(_ in L){var _=Math.random()>=.5?L[_][0]:L[_][1];M.push(_)}if(a==c){for(_ in m)M.push(m[_]);for(_ in O)M.push(O[_])}else if(a>c)for(_ in m)M.push(m[_]);else for(_ in O)M.push(O[_]);for(_ in M){var E=M[_];if(E.to=0;f--)"output"==e[f].type||e[f].connections.out.length+e[f].connections.gated.length==0?(e[f].type="output",o.output++,u.push(e[f]),e.splice(f,1)):"input"!=e[f].type&&e[f].connections.in.length||(e[f].type="input",o.input++,h.push(e[f]),e.splice(f,1));if(e=h.concat(e).concat(u),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a in e){for(var l in e[a].connections.out)o.connections.push(e[a].connections.out[l]);for(var l in e[a].connections.gated)o.gates.push(e[a].connections.gated[l]);0!=e[a].connections.self.weight&&o.selfconns.push(e[a].connections.self)}return o.nodes=e,o},Perceptron:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=[];t.push(new s(n[0]));for(var o=1;o0){var O=r.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=v.connect(v,e.Connection.ALL_TO_ELSE);d.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(d,e.Connection.ALL_TO_ALL),o.connect(p,e.Connection.ALL_TO_ALL),o.connect(g,e.Connection.ALL_TO_ALL)),h.push(d),h.push(p),h.push(v),h.push(g),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){var o=0;for(var e in t)o-=n[e]*Math.log(Math.max(t[e],1e-15))+(1-n[e])*Math.log(1-Math.max(t[e],1e-15));return o},MSE:function(n,t){var o=0;for(var e in t)o+=Math.pow(n[e]-t[e],2);return o/t.length},BINARY:function(n,t){var o=0;for(var e in t)o+=Math.round(2*n[e])!=Math.round(2*t[e]);return o},MAE:function(n,t){var o=0;for(var e in t)o+=Math.abs(n[e]-t[e]);return o/t.length},MAPE:function(n,t){var o=0;for(var e in t)o+=Math.abs((t[e]-n[e])/Math.max(n[e],1e-15));return o/t.length},MSLE:function(n,t){var o=0;for(var e in t)o+=Math.log(Math.max(n[e],1e-15))-Math.log(Math.max(t[e],1e-15));return o},HINGE:function(n,t){var o=0;for(var e in t)o+=Math.max(0,1-n[e]*t[e]);return o}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={SINGLE_POINT:{name:"SINGLE_POINT",config:[.4]},TWO_POINT:{name:"TWO_POINT",config:[.4,.9]},UNIFORM:{name:"UNIFORM"},AVERAGE:{name:"AVERAGE"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={OUTPUT:{name:"OUTPUT"},INPUT:{name:"INPUT"},SELF:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t=o(10),e={ADD_NODE:{name:"ADD_NODE"},SUB_NODE:{name:"SUB_NODE",keep_gates:!0},ADD_CONN:{name:"ADD_CONN"},SUB_CONN:{name:"REMOVE_CONN"},MOD_WEIGHT:{name:"MOD_WEIGHT",min:-1,max:1},MOD_BIAS:{name:"MOD_BIAS",min:-1,max:1},MOD_ACTIVATION:{name:"MOD_ACTIVATION",mutateOutput:!0,allowed:[t.LOGISTIC,t.TANH,t.RELU,t.IDENTITY,t.STEP,t.SOFTSIGN,t.SINUSOID,t.GAUSSIAN,t.BENT_IDENTITY,t.BIPOLAR,t.BIPOLAR_SIGMOID,t.HARD_TANH,t.ABSOLUTE]},ADD_SELF_CONN:{name:"ADD_SELF_CONN"},SUB_SELF_CONN:{name:"SUB_SELF_CONN"},ADD_GATE:{name:"ADD_GATE"},SUB_GATE:{name:"SUB_GATE"},ADD_BACK_CONN:{name:"ADD_BACK_CONN"},SUB_BACK_CONN:{name:"SUB_BACK_CONN"},SWAP_NODES:{name:"SWAP_NODES"}};e.ALL=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION,e.ADD_GATE,e.SUB_GATE,e.ADD_SELF_CONN,e.SUB_SELF_CONN,e.ADD_BACK_CONN,e.SUB_BACK_CONN],e.FFW=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION],n&&(n.exports=e)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FIXED:function(){return function(n,t){return n}},STEP:function(n,t){return n=n||.9,t=t||100,function(o,e){return o*Math.pow(n,Math.floor(e/t))}},EXP:function(n){return n=n||.999,function(t,o){return t*Math.pow(n,o)}},INV:function(n,t){return n=n||.001,t=t||2,function(o,e){return o*Math.pow(1+n*e,-t)}}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FITNESS_PROPORTIONATE:{name:"FITNESS_PROPORTIONATE"},POWER:{name:"POWER",power:4},TOURNAMENT:{name:"TOURNAMENT",size:5,probability:.5}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){var e,i,s={Node:o(2),Neat:o(9),Network:o(7),Methods:o(1),Architect:o(8),Group:o(5),Connection:o(4),Config:o(3),Layer:o(6)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.neataptic;s.ninja=function(){return window.neataptic=n,s}}(),window.neataptic=s)}])}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.18/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.18/neataptic.js deleted file mode 100644 index 0a7f7c5..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.18/neataptic.js +++ /dev/null @@ -1,3445 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - this.derivative = 0; - this.bias = 0; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var connection in this.connections.in){ - connection = this.connections.in[connection]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(node.connections.self.gater == this ? node.old : 0); - influences[influences.length - 1] += conn.weight * conn.from.activation; - } - } - - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var i = 0; i < nodes.length; i++){ - var node = nodes[i]; - var influence = influences[i]; - - var index = connection.xtrace.nodes.indexOf(node); - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - - // Update the gains of the gates - for(var connection in this.connections.gated){ - this.connections.gated[connection].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - // Error accumulator - var error = 0; - - momentum = momentum || 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for (var connection in this.connections.out) { - var connection = this.connections.out[connection]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var conn in this.connections.gated){ - conn = this.connections.gated[conn]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Learning rate - rate = rate || .3; - - // Adjust all the node's incoming connections - for (var connection in this.connections.in) { - var connection = this.connections.in[connection]; - - var gradient = this.error.projected * connection.elegibility; - - for(var i = 0; i < connection.xtrace.nodes.length; i++){ - var node = connection.xtrace.nodes[i]; - var value = connection.xtrace.values[i]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - - connection.weight += deltaWeight; - - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i in this.connections.out){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var connection in connections){ - connection = connections[connection]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for (var connection in this.connections.in) { - connection = this.connections.in[connection]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(conn in this.connections.out){ - conn = this.connections.out[conn]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(conn in this.connections.in){ - conn = this.connections.in[conn]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(node in this.nodes){ - if(this.nodes[node].type == 'input'){ - this.nodes[node].activate(input[node]); - } else if (this.nodes[node].type == 'output'){ - var activation = this.nodes[node].activate(); - output.push(activation); - } else { - if(training) this.nodes[node].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[node].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= 0; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var train in set) { - var input = set[train].input; - var target = set[train].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var test in set) { - input = set[test].input; - target = set[test].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var node in this.nodes){ - this.nodes[node].bias = values.bias || this.nodes[node].bias; - this.nodes[node].squash = values.squash || this.nodes[node].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iterations }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - offspring.nodes.push(node); - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(item in list){ - if(list[item] instanceof Group){ - for(var node in list[item].nodes){ - nodes.push(list[item].nodes[node]); - } - } else if(list[item] instanceof Layer){ - for(var group in list[item].nodes){ - for(var node in list[item].nodes[group].nodes){ - nodes.push(list[item].nodes[group].nodes[node]); - } - } - } else if(list[item] instanceof Node){ - nodes.push(list[item]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var node in nodes){ - for(var conn in nodes[node].connections.out){ - network.connections.push(nodes[node].connections.out[conn]); - } - for(var conn in nodes[node].connections.gated){ - network.gates.push(nodes[node].connections.gated[conn]); - } - if(nodes[node].connections.self.weight != 0){ - network.selfconns.push(nodes[node].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Construct the network - var network = Architect.Construct(nodes); - - // Initialise the weights - for(var conn in network.connections){ - var conn = network.connections[conn]; - // https://stats.stackexchange.com/a/248040/147931 - conn.weight = Math.random() * layers[0] * Math.sqrt(2 / layers[0]); - } - - // Return the network - return network; - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - if (!derivate) - return 1 / (1 + Math.exp(-x)); - var fx = Activation.LOGISTIC(x); - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if (derivate) - return 1 - Math.pow(Activation.TANH(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i in output){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i in output){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i in output){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.18/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.18/neataptic.min.js deleted file mode 100644 index c1875aa..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.18/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=18)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.derivative=0,this.bias=0,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t in this.connections.in)t=this.connections.in[t],this.state+=t.from.activation*t.weight*t.gain;this.activation=this.squash(this.state)*this.mask,this.derivative=this.squash(this.state,!0);var o=[],e=[];for(var i in this.connections.gated){i=this.connections.gated[i];var s=i.to,r=o.indexOf(s);r>-1?e[r]+=i.weight*i.from.activation:(o.push(s),e.push(s.connections.self.gater==this?s.old:0),e[e.length-1]+=i.weight*i.from.activation)}for(var t in this.connections.in){t=this.connections.in[t],t.elegibility=this.connections.self.gain*this.connections.self.weight*t.elegibility+t.from.activation*t.gain;for(var a=0;a-1?t.xtrace.values[r]=s.connections.self.gain*s.connections.self.weight*t.xtrace.values[r]+this.derivative*t.elegibility*c:(t.xtrace.nodes.push(s),t.xtrace.values.push(this.derivative*t.elegibility*c))}}for(var t in this.connections.gated)this.connections.gated[t].gain=this.activation;return this.activation},propagate:function(n,t,o){var e=0;if(t=t||0,"output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i in this.connections.out){var i=this.connections.out[i],s=i.to;e+=s.error.responsibility*i.weight*i.gain}this.error.projected=this.derivative*e,e=0;for(var r in this.connections.gated){r=this.connections.gated[r];var s=r.to,a=s.connections.self.gater==this?s.old:0;a+=r.weight*r.from.activation,e+=s.error.responsibility*a}this.error.gated=this.derivative*e,this.error.responsibility=this.error.projected+this.error.gated}if("constant"!=this.type){n=n||.3;for(var i in this.connections.in){for(var i=this.connections.in[i],c=this.error.projected*i.elegibility,h=0;h=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n in this.connections.in)n=this.connections.in[n],n.elegibility=0,n.xtrace={nodes:[],values:[]};this.error.responsibility=this.error.projected=this.error.gated=0,this.old=this.state=this.activation=0},mutate:function(n){if(void 0===n)throw new Error("No mutate method given!");if(!n.name in i.Mutation)throw new Error("This method does not exist!");switch(n){case c.MOD_ACTIVATION:var t=n.allowed[(n.allowed.indexOf(this.squash)+Math.floor(Math.random()*(n.allowed.length-1))+1)%n.allowed.length];this.squash=t;break;case c.MOD_BIAS:var o=Math.random()*(n.max-n.min)+n.min;this.bias+=o}},isProjectingTo:function(n){for(conn in this.connections.out)if(conn=this.connections.out[conn],conn.to==n)return!0;return!1},isProjectedBy:function(n){for(conn in this.connections.in)if(conn=this.connections.in[conn],conn.from==n)return!0;return!1},toJSON:function(){return{bias:this.bias,type:this.type,squash:this.squash.name,mask:this.mask}}},t.fromJSON=function(n){var o=new t;o.bias=n.bias,o.type=n.type,o.mask=n.mask;for(squash in a)if(a[squash].name==n.squash){o.squash=a[squash];break}return o}}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={warnings:!0};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n,t,o){this.from=n,this.to=t,this.gain=1,this.weight=void 0===o?.2*Math.random()-.1:o,this.gater=null,this.elegibility=0,this.previousDeltaWeight=0,this.xtrace={nodes:[],values:[]}}n&&(n.exports=t),t.prototype={toJSON:function(){return{weight:this.weight}}},t.innovationID=function(n,t){return.5*(n+t)*(n+t+1)+t}}).call(t,o(0)(n))},function(n,t,o){(function(n){function t(n){this.nodes=[],this.connections={in:[],out:[],self:[]};for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=this.nodes.length-this.output;i--)this.nodes[i].propagate(n,t,o[--e]);for(var i=this.nodes.length-this.output-1;i>=0;i--)this.nodes[i].propagate(n,t)},clear:function(){for(var n in this.nodes)this.nodes[n].clear()},connect:function(n,t,o){var e=n.connect(t,o);for(var i in e)i=e[i],n!=t?this.connections.push(i):this.selfconns.push(i);return e},disconnect:function(n,t){var o=n==t?this.selfconns:this.connections;for(conn in o){var e=o[conn];if(e.from==n&&e.to==t){null!=e.gater&&this.ungate(e),o.splice(conn,1);break}}n.disconnect(t)},gate:function(n,t){if(-1==this.nodes.indexOf(n))throw new Error("This node is not part of the network!");if(null!=t.gater)return void(r.warnings&&console.warn("This connection is already gated!"));n.gate(t),this.gates.push(t)},ungate:function(n){var t=this.gates.indexOf(n);if(-1==t)throw new Error("This connection is not gated!");this.gates.splice(t,1),n.gater.ungate(n)},remove:function(n){var t=this.nodes.indexOf(n);if(-1==t)throw new Error("This node does not exist in the network!");for(var o=[],e=[],i=n.connections.in.length-1;i>=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var d=Math.floor(Math.random()*c.length),f=c[d];this.gate(l,c[d]),c.splice(d,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],d=0;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(n.max-n.min)+n.min;t.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],d=this.input;d1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),p=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),g=this.nodes[f],L=p.bias,M=p.squash;p.bias=g.bias,p.squash=g.squash,g.bias=L,g.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,d=t.dropout||0,p=t.momentum||0,v=t.ratePolicy||s.Rate.FIXED(),g=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=d,f)var m=t.crossValidate.testSize,O=t.crossValidate.testError,w=Math.ceil((1-m)*n.length),_=n.slice(0,w),A=n.slice(w);for(var N=c,T=0,L=1;L>i&&(0==u||Tg&&(g=v,m=O),u&&p.generation%u==0&&console.log("generation",p.generation,"error",O.score,"cost error",v),l&&iteration%l.iterations==0&&l.function({error:v,iteration:c})}f&&m.clear();var w={error:g,generations:p.generation,time:Date.now()-d};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=o.input-1;i>=0;i--)o.nodes.splice(i,1);for(var i=n.nodes.length-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=n.output,d=0;d=.5?n.nodes[d]:o.nodes[d],g=p<.5?n.nodes[d]:o.nodes[d];void 0!==v&&"output"!=v.type||(v=g)}else if(Math.random()>=.5)var v=n.nodes[n.nodes.length+d-f];else var v=o.nodes[o.nodes.length+d-f];r.nodes.push(v)}for(v in r.nodes)r.nodes[v]=e.fromJSON(r.nodes[v].toJSON());var m={},O={},w=n.connections.concat(n.selfconns);for(_ in w){var _=w[_],A={weight:_.weight,from:n.nodes.indexOf(_.from),to:n.nodes.indexOf(_.to),gater:n.nodes.indexOf(_.gater)},N=i.innovationID(A.from,A.to);m[N]=A}var T=o.connections.concat(o.selfconns);for(_ in T){var _=T[_],A={weight:_.weight,from:o.nodes.indexOf(_.from),to:o.nodes.indexOf(_.to),gater:o.nodes.indexOf(_.gater)},N=i.innovationID(A.from,A.to);O[N]=A}var L={};for(var N in m)N in O&&(L[N]=[m[N],O[N]],delete m[N],delete O[N]);var M=[];for(_ in L){var _=Math.random()>=.5?L[_][0]:L[_][1];M.push(_)}if(a==c){for(_ in m)M.push(m[_]);for(_ in O)M.push(O[_])}else if(a>c)for(_ in m)M.push(m[_]);else for(_ in O)M.push(O[_]);for(_ in M){var E=M[_];if(E.to=0;f--)"output"==e[f].type||e[f].connections.out.length+e[f].connections.gated.length==0?(e[f].type="output",o.output++,u.push(e[f]),e.splice(f,1)):"input"!=e[f].type&&e[f].connections.in.length||(e[f].type="input",o.input++,h.push(e[f]),e.splice(f,1));if(e=h.concat(e).concat(u),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a in e){for(var l in e[a].connections.out)o.connections.push(e[a].connections.out[l]);for(var l in e[a].connections.gated)o.gates.push(e[a].connections.gated[l]);0!=e[a].connections.self.weight&&o.selfconns.push(e[a].connections.self)}return o.nodes=e,o},Perceptron:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=[];t.push(new s(n[0]));for(var o=1;o0){var O=r.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=v.connect(v,e.Connection.ALL_TO_ELSE);d.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(v,e.Connection.ALL_TO_ALL);d.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(d,e.Connection.ALL_TO_ALL),o.connect(p,e.Connection.ALL_TO_ALL),o.connect(g,e.Connection.ALL_TO_ALL)),h.push(d),h.push(p),h.push(v),h.push(g),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){var o=0;for(var e in t)o-=n[e]*Math.log(Math.max(t[e],1e-15))+(1-n[e])*Math.log(1-Math.max(t[e],1e-15));return o},MSE:function(n,t){var o=0;for(var e in t)o+=Math.pow(n[e]-t[e],2);return o/t.length},BINARY:function(n,t){var o=0;for(var e in t)o+=Math.round(2*n[e])!=Math.round(2*t[e]);return o},MAE:function(n,t){var o=0;for(var e in t)o+=Math.abs(n[e]-t[e]);return o/t.length},MAPE:function(n,t){var o=0;for(var e in t)o+=Math.abs((t[e]-n[e])/Math.max(n[e],1e-15));return o/t.length},MSLE:function(n,t){var o=0;for(var e in t)o+=Math.log(Math.max(n[e],1e-15))-Math.log(Math.max(t[e],1e-15));return o},HINGE:function(n,t){var o=0;for(var e in t)o+=Math.max(0,1-n[e]*t[e]);return o}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={SINGLE_POINT:{name:"SINGLE_POINT",config:[.4]},TWO_POINT:{name:"TWO_POINT",config:[.4,.9]},UNIFORM:{name:"UNIFORM"},AVERAGE:{name:"AVERAGE"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={OUTPUT:{name:"OUTPUT"},INPUT:{name:"INPUT"},SELF:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t=o(10),e={ADD_NODE:{name:"ADD_NODE"},SUB_NODE:{name:"SUB_NODE",keep_gates:!0},ADD_CONN:{name:"ADD_CONN"},SUB_CONN:{name:"REMOVE_CONN"},MOD_WEIGHT:{name:"MOD_WEIGHT",min:-1,max:1},MOD_BIAS:{name:"MOD_BIAS",min:-1,max:1},MOD_ACTIVATION:{name:"MOD_ACTIVATION",mutateOutput:!0,allowed:[t.LOGISTIC,t.TANH,t.RELU,t.IDENTITY,t.STEP,t.SOFTSIGN,t.SINUSOID,t.GAUSSIAN,t.BENT_IDENTITY,t.BIPOLAR,t.BIPOLAR_SIGMOID,t.HARD_TANH,t.ABSOLUTE]},ADD_SELF_CONN:{name:"ADD_SELF_CONN"},SUB_SELF_CONN:{name:"SUB_SELF_CONN"},ADD_GATE:{name:"ADD_GATE"},SUB_GATE:{name:"SUB_GATE"},ADD_BACK_CONN:{name:"ADD_BACK_CONN"},SUB_BACK_CONN:{name:"SUB_BACK_CONN"},SWAP_NODES:{name:"SWAP_NODES"}};e.ALL=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION,e.ADD_GATE,e.SUB_GATE,e.ADD_SELF_CONN,e.SUB_SELF_CONN,e.ADD_BACK_CONN,e.SUB_BACK_CONN],e.FFW=[e.ADD_NODE,e.SUB_NODE,e.ADD_CONN,e.SUB_CONN,e.MOD_WEIGHT,e.MOD_BIAS,e.MOD_ACTIVATION],n&&(n.exports=e)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FIXED:function(){return function(n,t){return n}},STEP:function(n,t){return n=n||.9,t=t||100,function(o,e){return o*Math.pow(n,Math.floor(e/t))}},EXP:function(n){return n=n||.999,function(t,o){return t*Math.pow(n,o)}},INV:function(n,t){return n=n||.001,t=t||2,function(o,e){return o*Math.pow(1+n*e,-t)}}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={FITNESS_PROPORTIONATE:{name:"FITNESS_PROPORTIONATE"},POWER:{name:"POWER",power:4},TOURNAMENT:{name:"TOURNAMENT",size:5,probability:.5}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){var e,i,s={Node:o(2),Neat:o(9),Network:o(7),Methods:o(1),Architect:o(8),Group:o(5),Connection:o(4),Config:o(3),Layer:o(6)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.neataptic;s.ninja=function(){return window.neataptic=n,s}}(),window.neataptic=s)}])}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.19/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.19/neataptic.js deleted file mode 100644 index 8feca63..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.19/neataptic.js +++ /dev/null @@ -1,3438 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - - connection.weight += deltaWeight; - - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var i = 0; i < set.length; i++) { - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iterations }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - offspring.nodes.push(node); - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(item in list){ - if(list[item] instanceof Group){ - for(var node in list[item].nodes){ - nodes.push(list[item].nodes[node]); - } - } else if(list[item] instanceof Layer){ - for(var group in list[item].nodes){ - for(var node in list[item].nodes[group].nodes){ - nodes.push(list[item].nodes[group].nodes[node]); - } - } - } else if(list[item] instanceof Node){ - nodes.push(list[item]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var node in nodes){ - for(var conn in nodes[node].connections.out){ - network.connections.push(nodes[node].connections.out[conn]); - } - for(var conn in nodes[node].connections.gated){ - network.gates.push(nodes[node].connections.gated[conn]); - } - if(nodes[node].connections.self.weight != 0){ - network.selfconns.push(nodes[node].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Construct the network - var network = Architect.Construct(nodes); - - // Initialise the weights - for(var conn in network.connections){ - var conn = network.connections[conn]; - // https://stats.stackexchange.com/a/248040/147931 - conn.weight = Math.random() * layers[0] * Math.sqrt(2 / layers[0]); - } - - // Return the network - return network; - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - if (!derivate) - return 1 / (1 + Math.exp(-x)); - var fx = Activation.LOGISTIC(x); - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if (derivate) - return 1 - Math.pow(Activation.TANH(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.19/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.19/neataptic.min.js deleted file mode 100644 index 40bf347..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.19/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=18)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t=0;t-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var t=0;t-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*h:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*h))}}return this.activation},propagate:function(n,t,o){t=t||0,n=n||.3;var e=0;if("output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i=0;i=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n=0;n=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=this.nodes.length-this.output;i--)this.nodes[i].propagate(n,t,o[--e]);for(var i=this.nodes.length-this.output-1;i>=this.input;i--)this.nodes[i].propagate(n,t)},clear:function(){for(var n=0;n=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var p=Math.floor(Math.random()*c.length),f=c[p];this.gate(l,c[p]),c.splice(p,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],p=0;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(n.max-n.min)+n.min;t.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[f],L=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=L,v.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,p=t.dropout||0,d=t.momentum||0,g=t.ratePolicy||s.Rate.FIXED(),v=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=p,f)var m=t.crossValidate.testSize,O=t.crossValidate.testError,w=Math.ceil((1-m)*n.length),_=n.slice(0,w),A=n.slice(w);for(var N=c,T=0,L=1;L>i&&(0==u||Tv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),l&&iteration%l.iterations==0&&l.function({error:g,iteration:c})}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=o.input-1;i>=0;i--)o.nodes.splice(i,1);for(var i=n.nodes.length-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=n.output,p=0;p=.5?n.nodes[p]:o.nodes[p],v=d<.5?n.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=n.nodes[n.nodes.length+p-f];else var g=o.nodes[o.nodes.length+p-f];r.nodes.push(g)}for(g in r.nodes)r.nodes[g]=e.fromJSON(r.nodes[g].toJSON());var m={},O={},w=n.connections.concat(n.selfconns);for(_ in w){var _=w[_],A={weight:_.weight,from:n.nodes.indexOf(_.from),to:n.nodes.indexOf(_.to),gater:n.nodes.indexOf(_.gater)},N=i.innovationID(A.from,A.to);m[N]=A}var T=o.connections.concat(o.selfconns);for(_ in T){var _=T[_],A={weight:_.weight,from:o.nodes.indexOf(_.from),to:o.nodes.indexOf(_.to),gater:o.nodes.indexOf(_.gater)},N=i.innovationID(A.from,A.to);O[N]=A}var L={};for(var N in m)N in O&&(L[N]=[m[N],O[N]],delete m[N],delete O[N]);var M=[];for(_ in L){var _=Math.random()>=.5?L[_][0]:L[_][1];M.push(_)}if(a==c){for(_ in m)M.push(m[_]);for(_ in O)M.push(O[_])}else if(a>c)for(_ in m)M.push(m[_]);else for(_ in O)M.push(O[_]);for(_ in M){var E=M[_];if(E.to=0;f--)"output"==e[f].type||e[f].connections.out.length+e[f].connections.gated.length==0?(e[f].type="output",o.output++,u.push(e[f]),e.splice(f,1)):"input"!=e[f].type&&e[f].connections.in.length||(e[f].type="input",o.input++,h.push(e[f]),e.splice(f,1));if(e=h.concat(e).concat(u),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a in e){for(var l in e[a].connections.out)o.connections.push(e[a].connections.out[l]);for(var l in e[a].connections.gated)o.gates.push(e[a].connections.gated[l]);0!=e[a].connections.self.weight&&o.selfconns.push(e[a].connections.self)}return o.nodes=e,o},Perceptron:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=[];t.push(new s(n[0]));for(var o=1;o0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),h.push(p),h.push(d),h.push(g),h.push(v),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - - connection.weight += deltaWeight; - - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(target instanceof Group){ - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } else if(target instanceof Node){ - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var connection in connections){ - connection = connections[connection]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(conn in connections){ - var connection = connections[conn]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(conn, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var i = 0; i < set.length; i++) { - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iterations }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - offspring.nodes.push(node); - } - - // Clear the node connections, make a copy - for(node in offspring.nodes){ - offspring.nodes[node] = Node.fromJSON(offspring.nodes[node].toJSON()); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - var n1connections = network1.connections.concat(network1.selfconns); - for(conn in n1connections){ - var conn = n1connections[conn]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns[id] = data; - } - - var n2connections = network2.connections.concat(network2.selfconns); - for(conn in n2connections){ - var conn = n2connections[conn]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns[id] = data; - } - - - // Split common conn genes from disjoint or excess conn genes - var commongenes = {}; - for(var id in n1conns) { - if(id in n2conns) { - commongenes[id] = [n1conns[id], n2conns[id]]; - delete n1conns[id]; - delete n2conns[id]; - } - } - - // Create a list of conn genes for the offspring - var connections = []; - for(conn in commongenes){ - var conn = Math.random() >= 0.5 ? commongenes[conn][0] : commongenes[conn][1]; - connections.push(conn); - } - - // Now add conn genes from the fittest parent (or both) - if(score1 == score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - for(conn in n2conns) connections.push(n2conns[conn]); - } else if(score1 > score2){ - for(conn in n1conns) connections.push(n1conns[conn]); - } else { - for(conn in n2conns) connections.push(n2conns[conn]); - } - - // Add common conn genes uniformly - for(conn in connections){ - var connData = connections[conn]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Construct the network - var network = Architect.Construct(nodes); - - // Initialise the weights - for(var conn in network.connections){ - var conn = network.connections[conn]; - // https://stats.stackexchange.com/a/248040/147931 - conn.weight = Math.random() * layers[0] * Math.sqrt(2 / layers[0]); - } - - // Return the network - return network; - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.20/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.20/neataptic.min.js deleted file mode 100644 index f491ae3..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.20/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=18)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=a.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=o(5),r=o(3),a=i.Activation,c=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t=0;t-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var t=0;t-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*h:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*h))}}return this.activation},propagate:function(n,t,o){t=t||0,n=n||.3;var e=0;if("output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i=0;i=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n=0;n=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=this.nodes.length-this.output;i--)this.nodes[i].propagate(n,t,o[--e]);for(var i=this.nodes.length-this.output-1;i>=this.input;i--)this.nodes[i].propagate(n,t)},clear:function(){for(var n=0;n=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var p=Math.floor(Math.random()*c.length),f=c[p];this.gate(l,c[p]),c.splice(p,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],p=0;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(n.max-n.min)+n.min;t.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[f],L=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=L,v.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,p=t.dropout||0,d=t.momentum||0,g=t.ratePolicy||s.Rate.FIXED(),v=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=p,f)var m=t.crossValidate.testSize,O=t.crossValidate.testError,w=Math.ceil((1-m)*n.length),_=n.slice(0,w),A=n.slice(w);for(var N=c,T=0,L=1;L>i&&(0==u||Tv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),l&&iteration%l.iterations==0&&l.function({error:g,iteration:c})}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=o.input-1;i>=0;i--)o.nodes.splice(i,1);for(var i=n.nodes.length-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=n.output,p=0;p=.5?n.nodes[p]:o.nodes[p],v=d<.5?n.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=n.nodes[n.nodes.length+p-f];else var g=o.nodes[o.nodes.length+p-f];r.nodes.push(g)}for(g in r.nodes)r.nodes[g]=e.fromJSON(r.nodes[g].toJSON());var m={},O={},w=n.connections.concat(n.selfconns);for(_ in w){var _=w[_],A={weight:_.weight,from:n.nodes.indexOf(_.from),to:n.nodes.indexOf(_.to),gater:n.nodes.indexOf(_.gater)},N=i.innovationID(A.from,A.to);m[N]=A}var T=o.connections.concat(o.selfconns);for(_ in T){var _=T[_],A={weight:_.weight,from:o.nodes.indexOf(_.from),to:o.nodes.indexOf(_.to),gater:o.nodes.indexOf(_.gater)},N=i.innovationID(A.from,A.to);O[N]=A}var L={};for(var N in m)N in O&&(L[N]=[m[N],O[N]],delete m[N],delete O[N]);var M=[];for(_ in L){var _=Math.random()>=.5?L[_][0]:L[_][1];M.push(_)}if(a==c){for(_ in m)M.push(m[_]);for(_ in O)M.push(O[_])}else if(a>c)for(_ in m)M.push(m[_]);else for(_ in O)M.push(O[_]);for(_ in M){var E=M[_];if(E.to=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,f.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(f),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),h.push(p),h.push(d),h.push(g),h.push(v),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - - connection.weight += deltaWeight; - - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(node.connections.self.weight == 0){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - error /= set.length; - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var i = 0; i < set.length; i++) { - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iterations }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && score1 >= score2){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Construct the network - var network = Architect.Construct(nodes); - - // Initialise the weights - for(var conn in network.connections){ - var conn = network.connections[conn]; - // https://stats.stackexchange.com/a/248040/147931 - conn.weight = Math.random() * layers[0] * Math.sqrt(2 / layers[0]); - } - - // Return the network - return network; - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.21/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.21/neataptic.min.js deleted file mode 100644 index 8bac465..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.21/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=18)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t=0;t-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var t=0;t-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*h:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*h))}}return this.activation},propagate:function(n,t,o){t=t||0,n=n||.3;var e=0;if("output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i=0;i=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n=0;n=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=this.nodes.length-this.output;i--)this.nodes[i].propagate(n,t,o[--e]);for(var i=this.nodes.length-this.output-1;i>=this.input;i--)this.nodes[i].propagate(n,t)},clear:function(){for(var n=0;n=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var p=Math.floor(Math.random()*c.length),f=c[p];this.gate(l,c[p]),c.splice(p,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],p=0;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(n.max-n.min)+n.min;t.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[f],L=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=L,v.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,p=t.dropout||0,d=t.momentum||0,g=t.ratePolicy||s.Rate.FIXED(),v=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=p,f)var m=t.crossValidate.testSize,O=t.crossValidate.testError,w=Math.ceil((1-m)*n.length),_=n.slice(0,w),A=n.slice(w);for(var N=c,T=0,L=1;L>i&&(0==u||Tv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),l&&iteration%l.iterations==0&&l.function({error:g,iteration:c})}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=o.input-1;i>=0;i--)o.nodes.splice(i,1);for(var i=n.nodes.length-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=n.output,p=0;p=.5?n.nodes[p]:o.nodes[p],v=d<.5?n.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=n.nodes[n.nodes.length+p-f];else var g=o.nodes[o.nodes.length+p-f];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var T=!1,L=w.length-1;L>=0;L--)if(O[p].from==w[L].from&&O[p].to==w[L].to){var _=Math.random()>=.5?O[p]:w[L];N.push(_),w[L]=[-1,-1];var T=!0;break}!T&&a>=c&&N.push(O[p])}if(c>=a)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,f.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(f),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),h.push(p),h.push(d),h.push(g),h.push(v),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - this.mask = 1; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - - connection.weight += deltaWeight; - - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - this.bias += rate * this.error.responsibility; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function(); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum / i; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var i = 0; i < set.length; i++) { - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:index, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:index, offset: 0}); - } else { - json.constraints[0].offsets.push({node:index, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:index, offset : -0.8 * height}); - } - - json.nodes.push({ - id: index, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iterations }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && score1 >= score2){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Construct the network - var network = Architect.Construct(nodes); - - // Initialise the weights - for(var conn in network.connections){ - var conn = network.connections[conn]; - // https://stats.stackexchange.com/a/248040/147931 - conn.weight = Math.random() * layers[0] * Math.sqrt(2 / layers[0]); - } - - // Return the network - return network; - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.22/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.22/neataptic.min.js deleted file mode 100644 index 72f0fc5..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.22/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=18)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t=0;t-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var t=0;t-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*h:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*h))}}return this.activation},propagate:function(n,t,o){t=t||0,n=n||.3;var e=0;if("output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i=0;i=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n=0;n=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=this.nodes.length-this.output;i--)this.nodes[i].propagate(n,t,o[--e]);for(var i=this.nodes.length-this.output-1;i>=this.input;i--)this.nodes[i].propagate(n,t)},clear:function(){for(var n=0;n=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var p=Math.floor(Math.random()*c.length),f=c[p];this.gate(l,c[p]),c.splice(p,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],p=0;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(n.max-n.min)+n.min;t.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[f],L=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=L,v.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,p=t.dropout||0,d=t.momentum||0,g=t.ratePolicy||s.Rate.FIXED(),v=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=p,f)var m=t.crossValidate.testSize,O=t.crossValidate.testError,w=Math.ceil((1-m)*n.length),_=n.slice(0,w),A=n.slice(w);for(var N=c,T=0,L=1;L>i&&(0==u||Tv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),l&&iteration%l.iterations==0&&l.function({error:g,iteration:c})}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=o.input-1;i>=0;i--)o.nodes.splice(i,1);for(var i=n.nodes.length-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=n.output,p=0;p=.5?n.nodes[p]:o.nodes[p],v=d<.5?n.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=n.nodes[n.nodes.length+p-f];else var g=o.nodes[o.nodes.length+p-f];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var T=!1,L=w.length-1;L>=0;L--)if(O[p].from==w[L].from&&O[p].to==w[L].to){var _=Math.random()>=.5?O[p]:w[L];N.push(_),w[L]=[-1,-1];var T=!0;break}!T&&a>=c&&N.push(O[p])}if(c>=a)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,f.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(f),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),h.push(p),h.push(d),h.push(g),h.push(v),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - connection.weight += deltaWeight; - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility + momentum * this.previousDeltaBias; - this.bias += deltaBias; - - this.previousDeltabias = deltaBias; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum / i; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var i = 0; i < set.length; i++) { - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && score1 >= score2){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal == true){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - for(genome in this.population){ - if(Math.random() <= this.mutationRate){ - for(var i = 0; i < this.mutationAmount; i++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[genome].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(genome in this.population){ - var score = this.fitness(this.population[genome]); - this.population[genome].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(genome in this.population){ - score += this.population[genome].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var genome in this.population){ - var score = this.population[genome].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var genome in this.population){ - genome = this.population[genome]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var genome in this.population){ - genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var genome in json){ - genome = json[genome]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = (x > 0 ? x : alpha * Math.exp(x) - alpha) * scale; - if(derivate) - return x > 0 ? scale : fx + alpha; - return fx; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.23/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.23/neataptic.min.js deleted file mode 100644 index b6b6cf5..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.23/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(n,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.neataptic=t():n.neataptic=t()}(this,function(){return function(n){function t(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return n[e].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var o={};return t.m=n,t.c=o,t.i=function(n){return n},t.d=function(n,o,e){t.o(n,o)||Object.defineProperty(n,o,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var o=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(o,"a",o),o},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=18)}([function(n,t){n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,t,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(t,e))&&(n.exports=i),void 0!==n&&n.exports&&(n.exports=s),"object"==typeof window&&(!function(){var n=window.methods;s.ninja=function(){return window.methods=n,s}}(),window.methods=s)},function(n,t,o){(function(n){function t(n){this.bias="input"==n?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=n||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaBias=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}n&&(n.exports=t);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;t.prototype={activate:function(n){if(void 0!==n)return this.activation=n,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var t=0;t-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var t=0;t-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*h:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*h))}}return this.activation},propagate:function(n,t,o){t=t||0,n=n||.3;var e=0;if("output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i=0;i=0;t--){var o=n[t],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var n=0;n=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,a){var c=[];if(n instanceof t){if(void 0===o&&(this!=n?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(n,t):this.nodes[e].propagate(n,t,o[e])},connect:function(n,o,e){if(n instanceof s||n instanceof i)var r=this.output.connect(n,o,e);else if(n instanceof t)var r=n.input(this,o,e);return r},gate:function(n,t){this.output.gate(n,t)},set:function(n){for(var t in this.nodes)t=this.nodes[t],t instanceof i?(void 0!==n.bias&&(t.bias=n.bias),t.squash=n.squash||t.squash,t.type=n.type||t.type):t instanceof s&&t.set(n)},disconnect:function(n,t){if(t=t||!1,n instanceof s)for(var o=0;o=this.nodes.length-this.output;i--)this.nodes[i].propagate(n,t,o[--e]);for(var i=this.nodes.length-this.output-1;i>=this.input;i--)this.nodes[i].propagate(n,t)},clear:function(){for(var n=0;n=0;i--){var r=n.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,n)}for(var a=[],i=n.connections.out.length-1;i>=0;i--){var r=n.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=n&&o.push(r.gater),a.push(r.to),this.disconnect(n,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var p=Math.floor(Math.random()*c.length),f=c[p];this.gate(l,c[p]),c.splice(p,1)}for(var i=n.connections.gated.length-1;i>=0;i--){var f=n.connections.gated[i];this.ungate(f)}this.disconnect(n,n),this.nodes.splice(t,1)},mutate:function(n){if(void 0===n)throw new Error("No (correct) mutate method given!");switch(n){case c.ADD_NODE:var t=this.connections[Math.floor(Math.random()*this.connections.length)],o=t.gater;this.disconnect(t.from,t.to);var i=this.nodes.indexOf(t.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(t.from,s)[0],u=this.connect(s,t.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],p=0;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var t=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(n.max-n.min)+n.min;t.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.MOD_ACTIVATION:if(!n.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(n.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(n);break;case c.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[f],L=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=L,v.squash=M}},train:function(n,t){t=t||{},void 0===t.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===t.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=t.log||!1,i=t.error||.05,a=t.cost||s.Cost.MSE,c=t.rate||.3,h=t.shuffle||!1,u=t.iterations||0,f=t.crossValidate||!1,l=t.clear||!1,p=t.dropout||0,d=t.momentum||0,g=t.batchSize||1,v=t.ratePolicy||s.Rate.FIXED(),m=t.schedule;if(void 0===t.iterations&&void 0===t.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===t.error&&(i=-1),this.dropout=p,f)var O=t.crossValidate.testSize,w=t.crossValidate.testError,_=Math.ceil((1-O)*n.length),A=n.slice(0,_),N=n.slice(_);for(var T=c,L=0,M=1;M>i&&(0==u||Lv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),l&&iteration%l.iterations==0&&l.function({error:g,iteration:d.generation})}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},t.fromJSON=function(n){var o=new t(n.input,n.output);o.dropout=n.dropout,o.nodes=[],o.connections=[];for(node in n.nodes)o.nodes.push(e.fromJSON(n.nodes[node]));for(i in n.connections){var i=n.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},t.merge=function(n,o){if(n=t.fromJSON(n.toJSON()),o=t.fromJSON(o.toJSON()),n.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=n.nodes[n.nodes.length-1-e]}for(var i=o.input-1;i>=0;i--)o.nodes.splice(i,1);for(var i=n.nodes.length-n.output;ic)var f=n.nodes.length;else var f=o.nodes.length;for(var l=n.output,p=0;p=.5?n.nodes[p]:o.nodes[p],v=d<.5?n.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=n.nodes[n.nodes.length+p-f];else var g=o.nodes[o.nodes.length+p-f];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var T=!1,L=w.length-1;L>=0;L--)if(O[p].from==w[L].from&&O[p].to==w[L].to){var _=Math.random()>=.5?O[p]:w[L];N.push(_),w[L]=[-1,-1];var T=!0;break}!T&&a>=c&&N.push(O[p])}if(c>=a)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,f.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(f),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),h.push(p),h.push(d),h.push(g),h.push(v),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var n=Array.prototype.slice.call(arguments);if(n.length<3)throw new Error("not enough layers (minimum 3) !!");var t=new s(n.shift()),o=new s(n.pop()),e=n,i=[];i.push(t);for(var c=t,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],h=0;h0?1:0},RELU:function(n,t){return t?n>0?1:0:n>0?n:0},SOFTSIGN:function(n,t){var o=1+Math.abs(n);return t?n/Math.pow(o,2):n/o},SINUSOID:function(n,t){return t?Math.cos(n):Math.sin(n)},GAUSSIAN:function(n,t){var o=Math.exp(-Math.pow(n,2));return t?-2*n*o:o},BENT_IDENTITY:function(n,t){var o=Math.sqrt(Math.pow(n,2)+1);return t?n/(2*o)+1:(o-1)/2+n},BIPOLAR:function(n,t){return t?0:n>0?1:-1},BIPOLAR_SIGMOID:function(n,t){var o=2/(1+Math.exp(-n))-1;return t?.5*(1+o)*(1-o):o},HARD_TANH:function(n,t){return t?n>-1&&n<1?1:0:Math.max(-1,Math.min(1,n))},ABSOLUTE:function(n,t){return t?n<0?-1:1:Math.abs(n)},INVERSE:function(n,t){return t?-1:1-n},SELU:function(n,t){var o=1.6732632423543772,e=1.0507009873554805,i=(n>0?n:o*Math.exp(n)-o)*e;return t?n>0?e:i+o:i}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};n&&(n.exports=t)}).call(t,o(0)(n))},function(n,t,o){(function(n){var t={CROSS_ENTROPY:function(n,t){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - connection.weight += deltaWeight; - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility + momentum * this.previousDeltaBias; - this.bias += deltaBias; - - this.previousDeltabias = deltaBias; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum / i; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var i = 0; i < set.length; i++) { - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && score1 >= score2){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.popsize; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = this.elitism; i < this.popsize; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.popsize; i++){ - var score = this.fitness(this.population[i]); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.popsize-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[tthis.popsize-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.popsize; i++){ - score += this.population[i].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.popsize; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.popsize)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = (x > 0 ? x : alpha * Math.exp(x) - alpha) * scale; - if(derivate) - return x > 0 ? scale : fx + alpha; - return fx; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.24/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.24/neataptic.min.js deleted file mode 100644 index 18c3e2e..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.24/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.neataptic=n():t.neataptic=n()}(this,function(){return function(t){function n(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return t[e].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var o={};return n.m=t,n.c=o,n.i=function(t){return t},n.d=function(t,o,e){n.o(t,o)||Object.defineProperty(t,o,{configurable:!1,enumerable:!0,get:e})},n.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(o,"a",o),o},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="",n(n.s=18)}([function(t,n){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,n,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(n,e))&&(t.exports=i),void 0!==t&&t.exports&&(t.exports=s),"object"==typeof window&&(!function(){var t=window.methods;s.ninja=function(){return window.methods=t,s}}(),window.methods=s)},function(t,n,o){(function(t){function n(t){this.bias="input"==t?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=t||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaBias=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}t&&(t.exports=n);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;n.prototype={activate:function(t){if(void 0!==t)return this.activation=t,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var n=0;n-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var n=0;n-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*h:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*h))}}return this.activation},propagate:function(t,n,o){n=n||0,t=t||.3;var e=0;if("output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i=0;i=0;n--){var o=t[n],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,a){var c=[];if(t instanceof n){if(void 0===o&&(this!=t?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,e){if(t instanceof s||t instanceof i)var r=this.output.connect(t,o,e);else if(t instanceof n)var r=t.input(this,o,e);return r},gate:function(t,n){this.output.gate(t,n)},set:function(t){for(var n in this.nodes)n=this.nodes[n],n instanceof i?(void 0!==t.bias&&(n.bias=t.bias),n.squash=t.squash||n.squash,n.type=t.type||n.type):n instanceof s&&n.set(t)},disconnect:function(t,n){if(n=n||!1,t instanceof s)for(var o=0;o=this.nodes.length-this.output;i--)this.nodes[i].propagate(t,n,o[--e]);for(var i=this.nodes.length-this.output-1;i>=this.input;i--)this.nodes[i].propagate(t,n)},clear:function(){for(var t=0;t=0;i--){var r=t.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,t)}for(var a=[],i=t.connections.out.length-1;i>=0;i--){var r=t.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),a.push(r.to),this.disconnect(t,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var p=Math.floor(Math.random()*c.length),f=c[p];this.gate(l,c[p]),c.splice(p,1)}for(var i=t.connections.gated.length-1;i>=0;i--){var f=t.connections.gated[i];this.ungate(f)}this.disconnect(t,t),this.nodes.splice(n,1)},mutate:function(t){if(void 0===t)throw new Error("No (correct) mutate method given!");switch(t){case c.ADD_NODE:var n=this.connections[Math.floor(Math.random()*this.connections.length)],o=n.gater;this.disconnect(n.from,n.to);var i=this.nodes.indexOf(n.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(n.from,s)[0],u=this.connect(s,n.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],p=0;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var n=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(t.max-t.min)+t.min;n.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(t);break;case c.MOD_ACTIVATION:if(!t.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(t.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(t);break;case c.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[f],L=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=L,v.squash=M}},train:function(t,n){n=n||{},void 0===n.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===n.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=n.log||!1,i=n.error||.05,a=n.cost||s.Cost.MSE,c=n.rate||.3,h=n.shuffle||!1,u=n.iterations||0,f=n.crossValidate||!1,l=n.clear||!1,p=n.dropout||0,d=n.momentum||0,g=n.batchSize||1,v=n.ratePolicy||s.Rate.FIXED(),m=n.schedule;if(void 0===n.iterations&&void 0===n.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===n.error&&(i=-1),this.dropout=p,f)var O=n.crossValidate.testSize,w=n.crossValidate.testError,_=Math.ceil((1-O)*t.length),A=t.slice(0,_),N=t.slice(_);for(var T=c,L=0,M=1;M>i&&(0==u||Lv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),l&&iteration%l.iterations==0&&l.function({error:g,iteration:d.generation})}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},n.fromJSON=function(t){var o=new n(t.input,t.output);o.dropout=t.dropout,o.nodes=[],o.connections=[];for(node in t.nodes)o.nodes.push(e.fromJSON(t.nodes[node]));for(i in t.connections){var i=t.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},n.merge=function(t,o){if(t=n.fromJSON(t.toJSON()),o=n.fromJSON(o.toJSON()),t.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=t.nodes[t.nodes.length-1-e]}for(var i=o.input-1;i>=0;i--)o.nodes.splice(i,1);for(var i=t.nodes.length-t.output;ic)var f=t.nodes.length;else var f=o.nodes.length;for(var l=t.output,p=0;p=.5?t.nodes[p]:o.nodes[p],v=d<.5?t.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=t.nodes[t.nodes.length+p-f];else var g=o.nodes[o.nodes.length+p-f];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var T=!1,L=w.length-1;L>=0;L--)if(O[p].from==w[L].from&&O[p].to==w[L].to){var _=Math.random()>=.5?O[p]:w[L];N.push(_),w[L]=[-1,-1];var T=!0;break}!T&&a>=c&&N.push(O[p])}if(c>=a)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,f.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(f),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),h.push(p),h.push(d),h.push(g),h.push(v),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var t=Array.prototype.slice.call(arguments);if(t.length<3)throw new Error("not enough layers (minimum 3) !!");var n=new s(t.shift()),o=new s(t.pop()),e=t,i=[];i.push(n);for(var c=n,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var h=[],e=0;e0?1:0},RELU:function(t,n){return n?t>0?1:0:t>0?t:0},SOFTSIGN:function(t,n){var o=1+Math.abs(t);return n?t/Math.pow(o,2):t/o},SINUSOID:function(t,n){return n?Math.cos(t):Math.sin(t)},GAUSSIAN:function(t,n){var o=Math.exp(-Math.pow(t,2));return n?-2*t*o:o},BENT_IDENTITY:function(t,n){var o=Math.sqrt(Math.pow(t,2)+1);return n?t/(2*o)+1:(o-1)/2+t},BIPOLAR:function(t,n){return n?0:t>0?1:-1},BIPOLAR_SIGMOID:function(t,n){var o=2/(1+Math.exp(-t))-1;return n?.5*(1+o)*(1-o):o},HARD_TANH:function(t,n){return n?t>-1&&t<1?1:0:Math.max(-1,Math.min(1,t))},ABSOLUTE:function(t,n){return n?t<0?-1:1:Math.abs(t)},INVERSE:function(t,n){return n?-1:1-t},SELU:function(t,n){var o=1.6732632423543772,e=1.0507009873554805,i=(t>0?t:o*Math.exp(t)-o)*e;return n?t>0?e:i+o:i}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={CROSS_ENTROPY:function(t,n){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - connection.weight += deltaWeight; - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility + momentum * this.previousDeltaBias; - this.bias += deltaBias; - - this.previousDeltabias = deltaBias; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var connection in connections){ - connection = connections[connection]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.in){ - conn = node.connections.in[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var conn in node.connections.out){ - conn = node.connections.out[conn]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - if(typeof values.bias != 'undefined'){ - this.nodes[node].bias = values.bias; - } - - this.nodes[node].squash = values.squash || this.nodes[node].squash; - this.nodes[node].type = values.type || this.nodes[node].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var node in this.nodes){ - node = this.nodes[node]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(index in this.connections.out){ - var conn = this.connections.out[index]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(index, 1); - break; - } - } - - if(twosided){ - for(index in this.connections.in){ - var conn = this.connections.in[index]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(index, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var node in this.nodes){ - this.nodes[node].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var group in layer.nodes){ - layer.nodes[group].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var input in inputs){ - input = inputs[input]; - for(var output in outputs){ - output = outputs[output]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var gater in gaters){ - if(connections.length == 0) break; - gater = gaters[gater]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var conn in allconnections){ - conn = allconnections[conn]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(conn in this.connections){ - conn = this.connections[conn]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum / i; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for (var i = 0; i < set.length; i++) { - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(connection in connections){ - connection = connections[connection]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(index in this.nodes){ - var node = this.nodes[index]; - var tojson = node.toJSON(); - tojson.index = index; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = index; - tojson.to = index; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(conn in this.connections){ - var conn = this.connections[conn]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(node in json.nodes){ - network.nodes.push(Node.fromJSON(json.nodes[node])); - } - - for(conn in json.connections){ - var conn = json.connections[conn]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(conn in network2.connections){ - conn = network2.connections[conn]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && score1 >= score2){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i]); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.popsize; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = this.elitism; i < this.popsize; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.popsize; i++){ - var score = this.fitness(this.population[i]); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.popsize-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.popsize-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.popsize; i++){ - score += this.population[i].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.popsize; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.popsize)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = (x > 0 ? x : alpha * Math.exp(x) - alpha) * scale; - if(derivate) - return x > 0 ? scale : fx + alpha; - return fx; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.25/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.25/neataptic.min.js deleted file mode 100644 index 981468d..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.25/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.neataptic=n():t.neataptic=n()}(this,function(){return function(t){function n(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return t[e].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var o={};return n.m=t,n.c=o,n.i=function(t){return t},n.d=function(t,o,e){n.o(t,o)||Object.defineProperty(t,o,{configurable:!1,enumerable:!0,get:e})},n.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(o,"a",o),o},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="",n(n.s=18)}([function(t,n){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,n,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(n,e))&&(t.exports=i),void 0!==t&&t.exports&&(t.exports=s),"object"==typeof window&&(!function(){var t=window.methods;s.ninja=function(){return window.methods=t,s}}(),window.methods=s)},function(t,n,o){(function(t){function n(t){this.bias="input"==t?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=t||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaBias=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}t&&(t.exports=n);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;n.prototype={activate:function(t){if(void 0!==t)return this.activation=t,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var n=0;n-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var n=0;n-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*h:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*h))}}return this.activation},propagate:function(t,n,o){n=n||0,t=t||.3;var e=0;if("output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i=0;i=0;n--){var o=t[n],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,a){var c=[];if(t instanceof n){if(void 0===o&&(this!=t?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var h=0;h=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,e){if(t instanceof s||t instanceof i)var r=this.output.connect(t,o,e);else if(t instanceof n)var r=t.input(this,o,e);return r},gate:function(t,n){this.output.gate(t,n)},set:function(t){for(var n in this.nodes)n=this.nodes[n],n instanceof i?(void 0!==t.bias&&(n.bias=t.bias),n.squash=t.squash||n.squash,n.type=t.type||n.type):n instanceof s&&n.set(t)},disconnect:function(t,n){if(n=n||!1,t instanceof s)for(var o=0;o=this.nodes.length-this.output;i--)this.nodes[i].propagate(t,n,o[--e]);for(var i=this.nodes.length-this.output-1;i>=this.input;i--)this.nodes[i].propagate(t,n)},clear:function(){for(var t=0;t=0;i--){var r=t.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,t)}for(var a=[],i=t.connections.out.length-1;i>=0;i--){var r=t.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),a.push(r.to),this.disconnect(t,r.to)}var c=[];for(var h in e){h=e[h];for(var u in a)if(u=a[u],!h.isProjectingTo(u)){var f=this.connect(h,u);c.push(f[0])}}for(var l in o){if(0==c.length)break;l=o[l];var p=Math.floor(Math.random()*c.length),f=c[p];this.gate(l,c[p]),c.splice(p,1)}for(var i=t.connections.gated.length-1;i>=0;i--){var f=t.connections.gated[i];this.ungate(f)}this.disconnect(t,t),this.nodes.splice(n,1)},mutate:function(t){if(void 0===t)throw new Error("No (correct) mutate method given!");switch(t){case c.ADD_NODE:var n=this.connections[Math.floor(Math.random()*this.connections.length)],o=n.gater;this.disconnect(n.from,n.to);var i=this.nodes.indexOf(n.to),s=new e("hidden",this.nodes.length);s.mutate(c.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var h=this.connect(n.from,s)[0],u=this.connect(s,n.to)[0];null!=o&&this.gate(o,Math.random()>=.5?h:u);break;case c.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case c.ADD_CONN:for(var l=[],p=0;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.to)>this.nodes.indexOf(A.from)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.MOD_WEIGHT:var n=this.connections[Math.floor(Math.random()*this.connections.length)],_=Math.random()*(t.max-t.min)+t.min;n.weight+=_;break;case c.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(t);break;case c.MOD_ACTIVATION:if(!t.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(t.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(t);break;case c.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&A.to.connections.in.length>1&&this.nodes.indexOf(A.from)>this.nodes.indexOf(A.to)&&O.push(A);if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var w=O[Math.floor(Math.random()*O.length)];this.disconnect(w.from,w.to);break;case c.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[f],L=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=L,v.squash=M}},train:function(t,n){n=n||{},void 0===n.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===n.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=n.log||!1,i=n.error||.05,a=n.cost||s.Cost.MSE,c=n.rate||.3,h=n.shuffle||!1,u=n.iterations||0,f=n.crossValidate||!1,l=n.clear||!1,p=n.dropout||0,d=n.momentum||0,g=n.batchSize||1,v=n.ratePolicy||s.Rate.FIXED(),m=n.schedule;if(void 0===n.iterations&&void 0===n.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===n.error&&(i=-1),this.dropout=p,f)var O=n.crossValidate.testSize,w=n.crossValidate.testError,_=Math.ceil((1-O)*t.length),A=t.slice(0,_),N=t.slice(_);for(var T=c,L=0,M=1;M>i&&(0==u||Lv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),l&&iteration%l.iterations==0&&l.function({error:g,iteration:d.generation})}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},n.fromJSON=function(t){var o=new n(t.input,t.output);o.dropout=t.dropout,o.nodes=[],o.connections=[];for(node in t.nodes)o.nodes.push(e.fromJSON(t.nodes[node]));for(i in t.connections){var i=t.connections[i],s=o.connect(o.nodes[i.from],o.nodes[i.to])[0];s.weight=i.weight,null!=i.gater&&o.gate(o.nodes[i.gater],s)}return o},n.merge=function(t,o){if(t=n.fromJSON(t.toJSON()),o=n.fromJSON(o.toJSON()),t.output!=o.input)throw new Error("Output size of network1 should be the same as the input size of network2!");for(conn in o.connections)if(conn=o.connections[conn],"input"==conn.from.type){var e=o.nodes.indexOf(conn.from);o.nodes[e];conn.from=t.nodes[t.nodes.length-1-e]}for(var i=o.input-1;i>=0;i--)o.nodes.splice(i,1);for(var i=t.nodes.length-t.output;ic)var f=t.nodes.length;else var f=o.nodes.length;for(var l=t.output,p=0;p=.5?t.nodes[p]:o.nodes[p],v=d<.5?t.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=t.nodes[t.nodes.length+p-f];else var g=o.nodes[o.nodes.length+p-f];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var T=!1,L=w.length-1;L>=0;L--)if(O[p].from==w[L].from&&O[p].to==w[L].to){var _=Math.random()>=.5?O[p]:w[L];N.push(_),w[L]=[-1,-1];var T=!0;break}!T&&a>=c&&N.push(O[p])}if(c>=a)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,f.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(f),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),h.push(p),h.push(d),h.push(g),h.push(v),f!=c.length-1&&h.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),h.push(o),a.Construct(h)},GRU:function(){var t=Array.prototype.slice.call(arguments);if(t.length<3)throw new Error("not enough layers (minimum 3) !!");var n=new s(t.shift()),o=new s(t.pop()),e=t,i=[];i.push(n);for(var c=n,h=0;hthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var h=[],e=0;e0?1:0},RELU:function(t,n){return n?t>0?1:0:t>0?t:0},SOFTSIGN:function(t,n){var o=1+Math.abs(t);return n?t/Math.pow(o,2):t/o},SINUSOID:function(t,n){return n?Math.cos(t):Math.sin(t)},GAUSSIAN:function(t,n){var o=Math.exp(-Math.pow(t,2));return n?-2*t*o:o},BENT_IDENTITY:function(t,n){var o=Math.sqrt(Math.pow(t,2)+1);return n?t/(2*o)+1:(o-1)/2+t},BIPOLAR:function(t,n){return n?0:t>0?1:-1},BIPOLAR_SIGMOID:function(t,n){var o=2/(1+Math.exp(-t))-1;return n?.5*(1+o)*(1-o):o},HARD_TANH:function(t,n){return n?t>-1&&t<1?1:0:Math.max(-1,Math.min(1,t))},ABSOLUTE:function(t,n){return n?t<0?-1:1:Math.abs(t)},INVERSE:function(t,n){return n?-1:1-t},SELU:function(t,n){var o=1.6732632423543772,e=1.0507009873554805,i=(t>0?t:o*Math.exp(t)-o)*e;return n?t>0?e:i+o:i}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={CROSS_ENTROPY:function(t,n){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask + momentum * connection.previousDeltaWeight; - connection.weight += deltaWeight; - connection.previousDeltaWeight = deltaWeight; - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility + momentum * this.previousDeltaBias; - this.bias += deltaBias; - - this.previousDeltabias = deltaBias; - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.out.length; j++){ - var conn = node.connections.out[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - if(typeof values.bias != 'undefined'){ - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var j = this.connections.in.length - 1; j >= 0; j--){ - var conn = this.connections.in[j]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var i = 0; i < layer.nodes.length; i++){ - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var i = 0; i < inputs.length; i++){ - var input = inputs[i]; - for(var j = 0; j < outputs.length; j++){ - var output = outputs[j]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var i = 0; i < gaters.length; i++){ - if(connections.length == 0) break; - var gater = gaters[i]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var i = 0; i < allconnections.length; i++){ - var conn = allconnections[i]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for(var i = 0; i < set.length; i++){ - var input = set[i].input; - var target = set[i].output; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, target); - - errorSum += costFunction(target, output); - } - return errorSum / i; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for(var i = 0; i < set.length; i++){ - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - var tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(var i = 0; i < json.nodes.length; i++){ - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for(var i = 0; i < json.connections.length; i++){ - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && score1 >= score2){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.popsize; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = this.elitism; i < this.popsize; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.popsize; i++){ - var score = this.fitness(this.population[i]); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.popsize-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.popsize-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.popsize; i++){ - score += this.population[i].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.popsize; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.popsize)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = (x > 0 ? x : alpha * Math.exp(x) - alpha) * scale; - if(derivate) - return x > 0 ? scale : fx + alpha; - return fx; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.26/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.26/neataptic.min.js deleted file mode 100644 index 9d50023..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.26/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.neataptic=n():t.neataptic=n()}(this,function(){return function(t){function n(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return t[e].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var o={};return n.m=t,n.c=o,n.i=function(t){return t},n.d=function(t,o,e){n.o(t,o)||Object.defineProperty(t,o,{configurable:!1,enumerable:!0,get:e})},n.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(o,"a",o),o},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="",n(n.s=18)}([function(t,n){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,n,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(n,e))&&(t.exports=i),void 0!==t&&t.exports&&(t.exports=s),"object"==typeof window&&(!function(){var t=window.methods;s.ninja=function(){return window.methods=t,s}}(),window.methods=s)},function(t,n,o){(function(t){function n(t){this.bias="input"==t?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=t||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaBias=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}t&&(t.exports=n);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;n.prototype={activate:function(t){if(void 0!==t)return this.activation=t,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var n=0;n-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var n=0;n-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*c:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*c))}}return this.activation},propagate:function(t,n,o){n=n||0,t=t||.3;var e=0;if("output"==this.type)this.error.responsibility=this.error.projected=o-this.activation;else{for(var i=0;i=0;n--){var o=t[n],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,a){var h=[];if(t instanceof n){if(void 0===o&&(this!=t?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var c=0;c=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[e]&&a.to==t.nodes[s]){this.connections.out.splice(r,1);break}}if(o)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[s]&&a.to==this.nodes[e]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var e=0;e=0;s--){var a=this.connections.out[s];if(a.from==this.nodes[e]&&a.to==t){this.connections.out.splice(s,1);break}}if(o)for(var s=this.connections.in.length-1;s>=0;s--){var a=this.connections.in[s];if(a.from==t&&a.to==this.nodes[e]){this.connections.in.splice(s,1);break}}}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,e){if(t instanceof s||t instanceof i)var r=this.output.connect(t,o,e);else if(t instanceof n)var r=t.input(this,o,e);return r},gate:function(t,n){this.output.gate(t,n)},set:function(t){for(var n=0;n=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[o]&&a.to==t.nodes[e]){this.connections.out.splice(r,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[e]&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var o=0;o=0;e--){var a=this.connections.out[e];if(a.from==this.nodes[o]&&a.to==t){this.connections.out.splice(e,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}},clear:function(){for(var t=0;t=this.nodes.length-this.output;i--)this.nodes[i].propagate(t,n,o[--e]);for(var i=this.nodes.length-this.output-1;i>=this.input;i--)this.nodes[i].propagate(t,n)},clear:function(){for(var t=0;t=0;i--){var r=t.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,t)}for(var a=[],i=t.connections.out.length-1;i>=0;i--){var r=t.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),a.push(r.to),this.disconnect(t,r.to)}for(var h=[],i=0;i=0;i--){var l=t.connections.gated[i];this.ungate(l)}this.disconnect(t,t),this.nodes.splice(n,1)},mutate:function(t){if(void 0===t)throw new Error("No (correct) mutate method given!");switch(t){case h.ADD_NODE:var n=this.connections[Math.floor(Math.random()*this.connections.length)],o=n.gater;this.disconnect(n.from,n.to);var i=this.nodes.indexOf(n.to),s=new e("hidden",this.nodes.length);s.mutate(h.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var c=this.connect(n.from,s)[0],u=this.connect(s,n.to)[0];null!=o&&this.gate(o,Math.random()>=.5?c:u);break;case h.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case h.ADD_CONN:for(var l=[],p=0;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.to)>this.nodes.indexOf(w.from)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.MOD_WEIGHT:var n=this.connections[Math.floor(Math.random()*this.connections.length)],A=Math.random()*(t.max-t.min)+t.min;n.weight+=A;break;case h.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(t);break;case h.MOD_ACTIVATION:if(!t.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(t.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(t);break;case h.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.from)>this.nodes.indexOf(w.to)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[f],T=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=T,v.squash=M}},train:function(t,n){n=n||{},void 0===n.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===n.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=n.log||!1,i=n.error||.05,a=n.cost||s.Cost.MSE,h=n.rate||.3,c=n.shuffle||!1,u=n.iterations||0,f=n.crossValidate||!1,l=n.clear||!1,p=n.dropout||0,d=n.momentum||0,g=n.batchSize||1,v=n.ratePolicy||s.Rate.FIXED(),m=n.schedule;if(void 0===n.iterations&&void 0===n.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===n.error&&(i=-1),this.dropout=p,f)var O=n.crossValidate.testSize,w=n.crossValidate.testError,_=Math.ceil((1-O)*t.length),A=t.slice(0,_),N=t.slice(_);for(var L=h,T=0,M=1;M>i&&(0==u||Tv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),l&&iteration%l.iterations==0&&l.function({error:g,iteration:d.generation})}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},n.fromJSON=function(t){var o=new n(t.input,t.output);o.dropout=t.dropout,o.nodes=[],o.connections=[];for(var i=0;i=0;e--)o.nodes.splice(e,1);for(var e=t.nodes.length-t.output;eh)var f=t.nodes.length;else var f=o.nodes.length;for(var l=t.output,p=0;p=.5?t.nodes[p]:o.nodes[p],v=d<.5?t.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=t.nodes[t.nodes.length+p-f];else var g=o.nodes[o.nodes.length+p-f];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var L=!1,T=w.length-1;T>=0;T--)if(O[p].from==w[T].from&&O[p].to==w[T].to){var _=Math.random()>=.5?O[p]:w[T];N.push(_),w[T]=[-1,-1];var L=!0;break}!L&&a>=h&&N.push(O[p])}if(h>=a)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,f.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(f),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),c.push(p),c.push(d),c.push(g),c.push(v),f!=h.length-1&&c.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),c.push(o),a.Construct(c)},GRU:function(){var t=Array.prototype.slice.call(arguments);if(t.length<3)throw new Error("not enough layers (minimum 3) !!");var n=new s(t.shift()),o=new s(t.pop()),e=t,i=[];i.push(n);for(var h=n,c=0;cthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],e=0;e0?1:0},RELU:function(t,n){return n?t>0?1:0:t>0?t:0},SOFTSIGN:function(t,n){var o=1+Math.abs(t);return n?t/Math.pow(o,2):t/o},SINUSOID:function(t,n){return n?Math.cos(t):Math.sin(t)},GAUSSIAN:function(t,n){var o=Math.exp(-Math.pow(t,2));return n?-2*t*o:o},BENT_IDENTITY:function(t,n){var o=Math.sqrt(Math.pow(t,2)+1);return n?t/(2*o)+1:(o-1)/2+t},BIPOLAR:function(t,n){return n?0:t>0?1:-1},BIPOLAR_SIGMOID:function(t,n){var o=2/(1+Math.exp(-t))-1;return n?.5*(1+o)*(1-o):o},HARD_TANH:function(t,n){return n?t>-1&&t<1?1:0:Math.max(-1,Math.min(1,t))},ABSOLUTE:function(t,n){return n?t<0?-1:1:Math.abs(t)},INVERSE:function(t,n){return n?-1:1-t},SELU:function(t,n){var o=1.6732632423543772,e=1.0507009873554805,i=(t>0?t:o*Math.exp(t)-o)*e;return n?t>0?e:i+o:i}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={CROSS_ENTROPY:function(t,n){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if(update){ - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if(update){ - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.out.length; j++){ - var conn = node.connections.out[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - if(typeof values.bias != 'undefined'){ - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var j = this.connections.in.length - 1; j >= 0; j--){ - var conn = this.connections.in[j]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var i = 0; i < layer.nodes.length; i++){ - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, update, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var i = 0; i < inputs.length; i++){ - var input = inputs[i]; - for(var j = 0; j < outputs.length; j++){ - var output = outputs[j]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var i = 0; i < gaters.length; i++){ - if(connections.length == 0) break; - var gater = gaters[i]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var i = 0; i < allconnections.length; i++){ - var conn = allconnections[i]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(batchSize > set.length) throw new Error("Batch size must be smaller or equal to dataset length!") - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for(var i = 0; i < set.length; i++){ - var input = set[i].input; - var target = set[i].output; - - var update = (i+1) % batchSize == 0 || (i+1) == set.length ? true : false; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / i; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for(var i = 0; i < set.length; i++){ - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - var tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - if(clear) genome.clear(); - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && neat.generation % schedule.iterations == 0){ - schedule.function({ error: error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(var i = 0; i < json.nodes.length; i++){ - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for(var i = 0; i < json.connections.length; i++){ - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && score1 >= score2){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.popsize; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = this.elitism; i < this.popsize; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.popsize; i++){ - var score = this.fitness(this.population[i]); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.popsize-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.popsize-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.popsize; i++){ - score += this.population[i].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.popsize; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.popsize)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[genome]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = (x > 0 ? x : alpha * Math.exp(x) - alpha) * scale; - if(derivate) - return x > 0 ? scale : fx + alpha; - return fx; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.27/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.27/neataptic.min.js deleted file mode 100644 index 23aa7d0..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.27/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.neataptic=n():t.neataptic=n()}(this,function(){return function(t){function n(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return t[e].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var o={};return n.m=t,n.c=o,n.i=function(t){return t},n.d=function(t,o,e){n.o(t,o)||Object.defineProperty(t,o,{configurable:!1,enumerable:!0,get:e})},n.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(o,"a",o),o},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="",n(n.s=18)}([function(t,n){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,n,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(n,e))&&(t.exports=i),void 0!==t&&t.exports&&(t.exports=s),"object"==typeof window&&(!function(){var t=window.methods;s.ninja=function(){return window.methods=t,s}}(),window.methods=s)},function(t,n,o){(function(t){function n(t){this.bias="input"==t?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=t||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaBias=0,this.totalDeltaBias=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}t&&(t.exports=n);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;n.prototype={activate:function(t){if(void 0!==t)return this.activation=t,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var n=0;n-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var n=0;n-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*c:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*c))}}return this.activation},propagate:function(t,n,o,e){n=n||0,t=t||.3;var i=0;if("output"==this.type)this.error.responsibility=this.error.projected=e-this.activation;else{for(var s=0;s=0;n--){var o=t[n],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,a){var h=[];if(t instanceof n){if(void 0===o&&(this!=t?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var c=0;c=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[e]&&a.to==t.nodes[s]){this.connections.out.splice(r,1);break}}if(o)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[s]&&a.to==this.nodes[e]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var e=0;e=0;s--){var a=this.connections.out[s];if(a.from==this.nodes[e]&&a.to==t){this.connections.out.splice(s,1);break}}if(o)for(var s=this.connections.in.length-1;s>=0;s--){var a=this.connections.in[s];if(a.from==t&&a.to==this.nodes[e]){this.connections.in.splice(s,1);break}}}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,e){if(t instanceof s||t instanceof i)var r=this.output.connect(t,o,e);else if(t instanceof n)var r=t.input(this,o,e);return r},gate:function(t,n){this.output.gate(t,n)},set:function(t){for(var n=0;n=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[o]&&a.to==t.nodes[e]){this.connections.out.splice(r,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[e]&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var o=0;o=0;e--){var a=this.connections.out[e];if(a.from==this.nodes[o]&&a.to==t){this.connections.out.splice(e,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}},clear:function(){for(var t=0;t=this.nodes.length-this.output;s--)this.nodes[s].propagate(t,n,o,e[--i]);for(var s=this.nodes.length-this.output-1;s>=this.input;s--)this.nodes[s].propagate(t,n,o)},clear:function(){for(var t=0;t=0;i--){var r=t.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,t)}for(var a=[],i=t.connections.out.length-1;i>=0;i--){var r=t.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),a.push(r.to),this.disconnect(t,r.to)}for(var h=[],i=0;i=0;i--){var l=t.connections.gated[i];this.ungate(l)}this.disconnect(t,t),this.nodes.splice(n,1)},mutate:function(t){if(void 0===t)throw new Error("No (correct) mutate method given!");switch(t){case h.ADD_NODE:var n=this.connections[Math.floor(Math.random()*this.connections.length)],o=n.gater;this.disconnect(n.from,n.to);var i=this.nodes.indexOf(n.to),s=new e("hidden",this.nodes.length);s.mutate(h.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var c=this.connect(n.from,s)[0],u=this.connect(s,n.to)[0];null!=o&&this.gate(o,Math.random()>=.5?c:u);break;case h.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case h.ADD_CONN:for(var l=[],p=0;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.to)>this.nodes.indexOf(w.from)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.MOD_WEIGHT:var n=this.connections[Math.floor(Math.random()*this.connections.length)],A=Math.random()*(t.max-t.min)+t.min;n.weight+=A;break;case h.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(t);break;case h.MOD_ACTIVATION:if(!t.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(t.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(t);break;case h.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.from)>this.nodes.indexOf(w.to)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[f],T=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=T,v.squash=M}},train:function(t,n){n=n||{},void 0===n.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===n.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=n.log||!1,i=n.error||.05,a=n.cost||s.Cost.MSE,h=n.rate||.3,c=n.shuffle||!1,u=n.iterations||0,f=n.crossValidate||!1,l=n.clear||!1,p=n.dropout||0,d=n.momentum||0,g=n.batchSize||1,v=n.ratePolicy||s.Rate.FIXED(),m=n.schedule;if(g>t.length)throw new Error("Batch size must be smaller or equal to dataset length!");if(void 0===n.iterations&&void 0===n.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===n.error&&(i=-1),this.dropout=p,f)var O=n.crossValidate.testSize,w=n.crossValidate.testError,_=Math.ceil((1-O)*t.length),A=t.slice(0,_),N=t.slice(_);for(var L=h,T=0,M=1;M>i&&(0==u||Tv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),l&&d.generation%l.iterations==0&&l.function({error:g,iteration:d.generation})}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns,w}},n.fromJSON=function(t){var o=new n(t.input,t.output);o.dropout=t.dropout,o.nodes=[],o.connections=[];for(var i=0;i=0;e--)o.nodes.splice(e,1);for(var e=t.nodes.length-t.output;eh)var f=t.nodes.length;else var f=o.nodes.length;for(var l=t.output,p=0;p=.5?t.nodes[p]:o.nodes[p],v=d<.5?t.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=t.nodes[t.nodes.length+p-f];else var g=o.nodes[o.nodes.length+p-f];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var L=!1,T=w.length-1;T>=0;T--)if(O[p].from==w[T].from&&O[p].to==w[T].to){var _=Math.random()>=.5?O[p]:w[T];N.push(_),w[T]=[-1,-1];var L=!0;break}!L&&a>=h&&N.push(O[p])}if(h>=a)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,f.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(f),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),c.push(p),c.push(d),c.push(g),c.push(v),f!=h.length-1&&c.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),c.push(o),a.Construct(c)},GRU:function(){var t=Array.prototype.slice.call(arguments);if(t.length<3)throw new Error("not enough layers (minimum 3) !!");var n=new s(t.shift()),o=new s(t.pop()),e=t,i=[];i.push(n);for(var h=n,c=0;cthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],e=0;e0?1:0},RELU:function(t,n){return n?t>0?1:0:t>0?t:0},SOFTSIGN:function(t,n){var o=1+Math.abs(t);return n?t/Math.pow(o,2):t/o},SINUSOID:function(t,n){return n?Math.cos(t):Math.sin(t)},GAUSSIAN:function(t,n){var o=Math.exp(-Math.pow(t,2));return n?-2*t*o:o},BENT_IDENTITY:function(t,n){var o=Math.sqrt(Math.pow(t,2)+1);return n?t/(2*o)+1:(o-1)/2+t},BIPOLAR:function(t,n){return n?0:t>0?1:-1},BIPOLAR_SIGMOID:function(t,n){var o=2/(1+Math.exp(-t))-1;return n?.5*(1+o)*(1-o):o},HARD_TANH:function(t,n){return n?t>-1&&t<1?1:0:Math.max(-1,Math.min(1,t))},ABSOLUTE:function(t,n){return n?t<0?-1:1:Math.abs(t)},INVERSE:function(t,n){return n?-1:1-t},SELU:function(t,n){var o=1.6732632423543772,e=1.0507009873554805,i=(t>0?t:o*Math.exp(t)-o)*e;return n?t>0?e:i+o:i}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={CROSS_ENTROPY:function(t,n){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if(update){ - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if(update){ - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.out.length; j++){ - var conn = node.connections.out[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - if(typeof values.bias != 'undefined'){ - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var j = this.connections.in.length - 1; j >= 0; j--){ - var conn = this.connections.in[j]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var i = 0; i < layer.nodes.length; i++){ - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, update, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var i = 0; i < inputs.length; i++){ - var input = inputs[i]; - for(var j = 0; j < outputs.length; j++){ - var output = outputs[j]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var i = 0; i < gaters.length; i++){ - if(connections.length == 0) break; - var gater = gaters[i]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var i = 0; i < allconnections.length; i++){ - var conn = allconnections[i]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(batchSize > set.length) throw new Error("Batch size must be smaller or equal to dataset length!") - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for(var i = 0; i < set.length; i++){ - var input = set[i].input; - var target = set[i].output; - - var update = (i+1) % batchSize == 0 || (i+1) == set.length ? true : false; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for(var i = 0; i < set.length; i++){ - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - var tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && neat.generation % schedule.iterations == 0){ - schedule.function({ error: error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - if(bestGenome != null){ - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - } - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(var i = 0; i < json.nodes.length; i++){ - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for(var i = 0; i < json.connections.length; i++){ - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && score1 >= score2){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - for(var i = 0; i < this.elitism; i++){ - newPopulation.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - // Reset the scores - for(var i = 0; i < this.popsize; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = this.elitism; i < this.popsize; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[i]; - if(this.clear) genome.clear(); - var score = this.fitness(genome); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.popsize-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.popsize-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.popsize; i++){ - score += this.population[i].score; - } - - return score / this.popsize; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.popsize); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.popsize; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.popsize; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.popsize)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.popsize; i++){ - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = (x > 0 ? x : alpha * Math.exp(x) - alpha) * scale; - if(derivate) - return x > 0 ? scale : fx + alpha; - return fx; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.28/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.28/neataptic.min.js deleted file mode 100644 index c6a11fa..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.28/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.neataptic=n():t.neataptic=n()}(this,function(){return function(t){function n(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return t[e].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var o={};return n.m=t,n.c=o,n.i=function(t){return t},n.d=function(t,o,e){n.o(t,o)||Object.defineProperty(t,o,{configurable:!1,enumerable:!0,get:e})},n.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(o,"a",o),o},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="",n(n.s=18)}([function(t,n){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,n,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(n,e))&&(t.exports=i),void 0!==t&&t.exports&&(t.exports=s),"object"==typeof window&&(!function(){var t=window.methods;s.ninja=function(){return window.methods=t,s}}(),window.methods=s)},function(t,n,o){(function(t){function n(t){this.bias="input"==t?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=t||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaBias=0,this.totalDeltaBias=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}t&&(t.exports=n);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;n.prototype={activate:function(t){if(void 0!==t)return this.activation=t,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var n=0;n-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var n=0;n-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*c:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*c))}}return this.activation},propagate:function(t,n,o,e){n=n||0,t=t||.3;var i=0;if("output"==this.type)this.error.responsibility=this.error.projected=e-this.activation;else{for(var s=0;s=0;n--){var o=t[n],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,a){var h=[];if(t instanceof n){if(void 0===o&&(this!=t?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var c=0;c=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[e]&&a.to==t.nodes[s]){this.connections.out.splice(r,1);break}}if(o)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[s]&&a.to==this.nodes[e]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var e=0;e=0;s--){var a=this.connections.out[s];if(a.from==this.nodes[e]&&a.to==t){this.connections.out.splice(s,1);break}}if(o)for(var s=this.connections.in.length-1;s>=0;s--){var a=this.connections.in[s];if(a.from==t&&a.to==this.nodes[e]){this.connections.in.splice(s,1);break}}}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,e){if(t instanceof s||t instanceof i)var r=this.output.connect(t,o,e);else if(t instanceof n)var r=t.input(this,o,e);return r},gate:function(t,n){this.output.gate(t,n)},set:function(t){for(var n=0;n=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[o]&&a.to==t.nodes[e]){this.connections.out.splice(r,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[e]&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var o=0;o=0;e--){var a=this.connections.out[e];if(a.from==this.nodes[o]&&a.to==t){this.connections.out.splice(e,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}},clear:function(){for(var t=0;t=this.nodes.length-this.output;s--)this.nodes[s].propagate(t,n,o,e[--i]);for(var s=this.nodes.length-this.output-1;s>=this.input;s--)this.nodes[s].propagate(t,n,o)},clear:function(){for(var t=0;t=0;i--){var r=t.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,t)}for(var a=[],i=t.connections.out.length-1;i>=0;i--){var r=t.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),a.push(r.to),this.disconnect(t,r.to)}for(var h=[],i=0;i=0;i--){var l=t.connections.gated[i];this.ungate(l)}this.disconnect(t,t),this.nodes.splice(n,1)},mutate:function(t){if(void 0===t)throw new Error("No (correct) mutate method given!");switch(t){case h.ADD_NODE:var n=this.connections[Math.floor(Math.random()*this.connections.length)],o=n.gater;this.disconnect(n.from,n.to);var i=this.nodes.indexOf(n.to),s=new e("hidden",this.nodes.length);s.mutate(h.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var c=this.connect(n.from,s)[0],u=this.connect(s,n.to)[0];null!=o&&this.gate(o,Math.random()>=.5?c:u);break;case h.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var f=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[f]);break;case h.ADD_CONN:for(var l=[],p=0;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.to)>this.nodes.indexOf(w.from)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.MOD_WEIGHT:var n=this.connections[Math.floor(Math.random()*this.connections.length)],A=Math.random()*(t.max-t.min)+t.min;n.weight+=A;break;case h.MOD_BIAS:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[f];s.mutate(t);break;case h.MOD_ACTIVATION:if(!t.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var f=Math.floor(Math.random()*(this.nodes.length-(t.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[f];s.mutate(t);break;case h.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.from)>this.nodes.indexOf(w.to)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.SWAP_NODES:var f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[f],f=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[f],T=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=T,v.squash=M}},train:function(t,n){n=n||{},void 0===n.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===n.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=n.log||!1,i=n.error||.05,a=n.cost||s.Cost.MSE,h=n.rate||.3,c=n.shuffle||!1,u=n.iterations||0,f=n.crossValidate||!1,l=n.clear||!1,p=n.dropout||0,d=n.momentum||0,g=n.batchSize||1,v=n.ratePolicy||s.Rate.FIXED(),m=n.schedule;if(g>t.length)throw new Error("Batch size must be smaller or equal to dataset length!");if(void 0===n.iterations&&void 0===n.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===n.error&&(i=-1),this.dropout=p,f)var O=n.crossValidate.testSize,w=n.crossValidate.testError,_=Math.ceil((1-O)*t.length),A=t.slice(0,_),N=t.slice(_);for(var L=h,T=0,M=1;M>i&&(0==u||Tv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),l&&d.generation%l.iterations==0&&l.function({error:g,iteration:d.generation})}f&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return null!=m&&(this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns),w}},n.fromJSON=function(t){var o=new n(t.input,t.output);o.dropout=t.dropout,o.nodes=[],o.connections=[];for(var i=0;i=0;e--)o.nodes.splice(e,1);for(var e=t.nodes.length-t.output;eh)var f=t.nodes.length;else var f=o.nodes.length;for(var l=t.output,p=0;p=.5?t.nodes[p]:o.nodes[p],v=d<.5?t.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=t.nodes[t.nodes.length+p-f];else var g=o.nodes[o.nodes.length+p-f];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var L=!1,T=w.length-1;T>=0;T--)if(O[p].from==w[T].from&&O[p].to==w[T].to){var _=Math.random()>=.5?O[p]:w[T];N.push(_),w[T]=[-1,-1];var L=!0;break}!L&&a>=h&&N.push(O[p])}if(h>=a)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,f.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(f),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),c.push(p),c.push(d),c.push(g),c.push(v),f!=h.length-1&&c.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),c.push(o),a.Construct(c)},GRU:function(){var t=Array.prototype.slice.call(arguments);if(t.length<3)throw new Error("not enough layers (minimum 3) !!");var n=new s(t.shift()),o=new s(t.pop()),e=t,i=[];i.push(n);for(var h=n,c=0;cthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],e=0;e0?1:0},RELU:function(t,n){return n?t>0?1:0:t>0?t:0},SOFTSIGN:function(t,n){var o=1+Math.abs(t);return n?t/Math.pow(o,2):t/o},SINUSOID:function(t,n){return n?Math.cos(t):Math.sin(t)},GAUSSIAN:function(t,n){var o=Math.exp(-Math.pow(t,2));return n?-2*t*o:o},BENT_IDENTITY:function(t,n){var o=Math.sqrt(Math.pow(t,2)+1);return n?t/(2*o)+1:(o-1)/2+t},BIPOLAR:function(t,n){return n?0:t>0?1:-1},BIPOLAR_SIGMOID:function(t,n){var o=2/(1+Math.exp(-t))-1;return n?.5*(1+o)*(1-o):o},HARD_TANH:function(t,n){return n?t>-1&&t<1?1:0:Math.max(-1,Math.min(1,t))},ABSOLUTE:function(t,n){return n?t<0?-1:1:Math.abs(t)},INVERSE:function(t,n){return n?-1:1-t},SELU:function(t,n){var o=1.6732632423543772,e=1.0507009873554805,i=(t>0?t:o*Math.exp(t)-o)*e;return n?t>0?e:i+o:i}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={CROSS_ENTROPY:function(t,n){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if(update){ - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if(update){ - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.out.length; j++){ - var conn = node.connections.out[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - if(typeof values.bias != 'undefined'){ - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var j = this.connections.in.length - 1; j >= 0; j--){ - var conn = this.connections.in[j]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var i = 0; i < layer.nodes.length; i++){ - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, update, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var i = 0; i < inputs.length; i++){ - var input = inputs[i]; - for(var j = 0; j < outputs.length; j++){ - var output = outputs[j]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var i = 0; i < gaters.length; i++){ - if(connections.length == 0) break; - var gater = gaters[i]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var i = 0; i < allconnections.length; i++){ - var conn = allconnections[i]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(batchSize > set.length) throw new Error("Batch size must be smaller or equal to dataset length!") - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for(var i = 0; i < set.length; i++){ - var input = set[i].input; - var target = set[i].output; - - var update = (i+1) % batchSize == 0 || (i+1) == set.length ? true : false; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for(var i = 0; i < set.length; i++){ - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - var tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && neat.generation % schedule.iterations == 0){ - schedule.function({ error: error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - if(bestGenome != null){ - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - } - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(var i = 0; i < json.nodes.length; i++){ - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for(var i = 0; i < json.connections.length; i++){ - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, method){ - /*if(typeof method == 'undefined'){ - throw new Error('No crossover method given!'); - } else if(!method.name in Methods.Crossover){ - throw new Error('This method does not exist!'); - } else */if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && score1 >= score2){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - var elitists = []; - for(var i = 0; i < this.elitism; i++){ - elitists.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - for(var i = 0; i < elitists.length; i++){ - this.population.push(elitists[i]); - } - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - if(this.equal){ - parent1.score = 0; - parent2.score = 0; - } - - //var crossoverMethod = this.crossover[Math.floor(Math.random()*this.crossover.length)]; - return Network.crossOver(parent1, parent2); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = 0; i < this.population.length; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - if(this.clear) genome.clear(); - var score = this.fitness(genome); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.population.length; i++){ - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.population.length; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = (x > 0 ? x : alpha * Math.exp(x) - alpha) * scale; - if(derivate) - return x > 0 ? scale : fx + alpha; - return fx; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.29/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.29/neataptic.min.js deleted file mode 100644 index 1d27544..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.29/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.neataptic=n():t.neataptic=n()}(this,function(){return function(t){function n(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return t[e].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var o={};return n.m=t,n.c=o,n.i=function(t){return t},n.d=function(t,o,e){n.o(t,o)||Object.defineProperty(t,o,{configurable:!1,enumerable:!0,get:e})},n.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(o,"a",o),o},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="",n(n.s=18)}([function(t,n){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,n,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(n,e))&&(t.exports=i),void 0!==t&&t.exports&&(t.exports=s),"object"==typeof window&&(!function(){var t=window.methods;s.ninja=function(){return window.methods=t,s}}(),window.methods=s)},function(t,n,o){(function(t){function n(t){this.bias="input"==t?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=t||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaBias=0,this.totalDeltaBias=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}t&&(t.exports=n);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;n.prototype={activate:function(t){if(void 0!==t)return this.activation=t,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var n=0;n-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var n=0;n-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*c:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*c))}}return this.activation},propagate:function(t,n,o,e){n=n||0,t=t||.3;var i=0;if("output"==this.type)this.error.responsibility=this.error.projected=e-this.activation;else{for(var s=0;s=0;n--){var o=t[n],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,a){var h=[];if(t instanceof n){if(void 0===o&&(this!=t?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var c=0;c=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[e]&&a.to==t.nodes[s]){this.connections.out.splice(r,1);break}}if(o)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[s]&&a.to==this.nodes[e]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var e=0;e=0;s--){var a=this.connections.out[s];if(a.from==this.nodes[e]&&a.to==t){this.connections.out.splice(s,1);break}}if(o)for(var s=this.connections.in.length-1;s>=0;s--){var a=this.connections.in[s];if(a.from==t&&a.to==this.nodes[e]){this.connections.in.splice(s,1);break}}}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,e){if(t instanceof s||t instanceof i)var r=this.output.connect(t,o,e);else if(t instanceof n)var r=t.input(this,o,e);return r},gate:function(t,n){this.output.gate(t,n)},set:function(t){for(var n=0;n=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[o]&&a.to==t.nodes[e]){this.connections.out.splice(r,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[e]&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var o=0;o=0;e--){var a=this.connections.out[e];if(a.from==this.nodes[o]&&a.to==t){this.connections.out.splice(e,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}},clear:function(){for(var t=0;t=this.nodes.length-this.output;s--)this.nodes[s].propagate(t,n,o,e[--i]);for(var s=this.nodes.length-this.output-1;s>=this.input;s--)this.nodes[s].propagate(t,n,o)},clear:function(){for(var t=0;t=0;i--){var r=t.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,t)}for(var a=[],i=t.connections.out.length-1;i>=0;i--){var r=t.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),a.push(r.to),this.disconnect(t,r.to)}for(var h=[],i=0;i=0;i--){var f=t.connections.gated[i];this.ungate(f)}this.disconnect(t,t),this.nodes.splice(n,1)},mutate:function(t){if(void 0===t)throw new Error("No (correct) mutate method given!");switch(t){case h.ADD_NODE:var n=this.connections[Math.floor(Math.random()*this.connections.length)],o=n.gater;this.disconnect(n.from,n.to);var i=this.nodes.indexOf(n.to),s=new e("hidden",this.nodes.length);s.mutate(h.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var c=this.connect(n.from,s)[0],u=this.connect(s,n.to)[0];null!=o&&this.gate(o,Math.random()>=.5?c:u);break;case h.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var l=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[l]);break;case h.ADD_CONN:for(var f=[],p=0;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.to)>this.nodes.indexOf(w.from)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.MOD_WEIGHT:var n=this.connections[Math.floor(Math.random()*this.connections.length)],A=Math.random()*(t.max-t.min)+t.min;n.weight+=A;break;case h.MOD_BIAS:var l=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[l];s.mutate(t);break;case h.MOD_ACTIVATION:if(!t.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var l=Math.floor(Math.random()*(this.nodes.length-(t.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[l];s.mutate(t);break;case h.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.from)>this.nodes.indexOf(w.to)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.SWAP_NODES:var l=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[l],l=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[l],T=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=T,v.squash=M}},train:function(t,n){n=n||{},void 0===n.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===n.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=n.log||!1,i=n.error||.05,a=n.cost||s.Cost.MSE,h=n.rate||.3,c=n.shuffle||!1,u=n.iterations||0,l=n.crossValidate||!1,f=n.clear||!1,p=n.dropout||0,d=n.momentum||0,g=n.batchSize||1,v=n.ratePolicy||s.Rate.FIXED(),m=n.schedule;if(g>t.length)throw new Error("Batch size must be smaller or equal to dataset length!");if(void 0===n.iterations&&void 0===n.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===n.error&&(i=-1),this.dropout=p,l)var O=n.crossValidate.testSize,w=n.crossValidate.testError,_=Math.ceil((1-O)*t.length),A=t.slice(0,_),N=t.slice(_);for(var L=h,T=0,M=1;M>i&&(0==u||Tv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),f&&d.generation%f.iterations==0&&f.function({error:g,iteration:d.generation})}l&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return null!=m&&(this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns),w}},n.fromJSON=function(t){var o=new n(t.input,t.output);o.dropout=t.dropout,o.nodes=[],o.connections=[];for(var i=0;i=0;e--)o.nodes.splice(e,1);for(var e=t.nodes.length-t.output;eh)var l=t.nodes.length;else var l=o.nodes.length;for(var f=t.output,p=0;p=.5?t.nodes[p]:o.nodes[p],v=d<.5?t.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=t.nodes[t.nodes.length+p-l];else var g=o.nodes[o.nodes.length+p-l];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var L=!1,T=w.length-1;T>=0;T--)if(O[p].from==w[T].from&&O[p].to==w[T].to){var _=Math.random()>=.5?O[p]:w[T];N.push(_),w[T]=[-1,-1];var L=!0;break}!L&&a>=h&&N.push(O[p])}if(h>=a)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,l.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(l),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),c.push(p),c.push(d),c.push(g),c.push(v),l!=h.length-1&&c.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),c.push(o),a.Construct(c)},GRU:function(){var t=Array.prototype.slice.call(arguments);if(t.length<3)throw new Error("not enough layers (minimum 3) !!");var n=new s(t.shift()),o=new s(t.pop()),e=t,i=[];i.push(n);for(var h=n,c=0;cthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],e=0;e0?1:0},RELU:function(t,n){return n?t>0?1:0:t>0?t:0},SOFTSIGN:function(t,n){var o=1+Math.abs(t);return n?t/Math.pow(o,2):t/o},SINUSOID:function(t,n){return n?Math.cos(t):Math.sin(t)},GAUSSIAN:function(t,n){var o=Math.exp(-Math.pow(t,2));return n?-2*t*o:o},BENT_IDENTITY:function(t,n){var o=Math.sqrt(Math.pow(t,2)+1);return n?t/(2*o)+1:(o-1)/2+t},BIPOLAR:function(t,n){return n?0:t>0?1:-1},BIPOLAR_SIGMOID:function(t,n){var o=2/(1+Math.exp(-t))-1;return n?.5*(1+o)*(1-o):o},HARD_TANH:function(t,n){return n?t>-1&&t<1?1:0:Math.max(-1,Math.min(1,t))},ABSOLUTE:function(t,n){return n?t<0?-1:1:Math.abs(t)},INVERSE:function(t,n){return n?-1:1-t},SELU:function(t,n){var o=1.6732632423543772,e=1.0507009873554805,i=(t>0?t:o*Math.exp(t)-o)*e;return n?t>0?e:i+o:i}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={CROSS_ENTROPY:function(t,n){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if(update){ - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if(update){ - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: true -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.out.length; j++){ - var conn = node.connections.out[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - if(typeof values.bias != 'undefined'){ - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var j = this.connections.in.length - 1; j >= 0; j--){ - var conn = this.connections.in[j]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var i = 0; i < layer.nodes.length; i++){ - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, update, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var i = 0; i < inputs.length; i++){ - var input = inputs[i]; - for(var j = 0; j < outputs.length; j++){ - var output = outputs[j]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var i = 0; i < gaters.length; i++){ - if(connections.length == 0) break; - var gater = gaters[i]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var i = 0; i < allconnections.length; i++){ - var conn = allconnections[i]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Input nodes are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(batchSize > set.length) throw new Error("Batch size must be smaller or equal to dataset length!") - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for(var i = 0; i < set.length; i++){ - var input = set[i].input; - var target = set[i].output; - - var update = (i+1) % batchSize == 0 || (i+1) == set.length ? true : false; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for(var i = 0; i < set.length; i++){ - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - var tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - options = options || {}; - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitness(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitness, options); - - var error = -Infinity; - var bestError = -Infinity; - var bestGenome = null; - - while(error < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - - if(clear) fittest.clear(); - error = -fittest.test(set).error - (fittest.nodes.length + fittest.connections.length + fittest.gates.length) * growth; - - if(error > bestError){ - bestError = error; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'error', fittest.score, 'cost error', error); - } - - if(schedule && neat.generation % schedule.iterations == 0){ - schedule.function({ error: error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestError, - generations: neat.generation, - time: Date.now() - start - }; - - if(bestGenome != null){ - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - } - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(var i = 0; i < json.nodes.length; i++){ - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for(var i = 0; i < json.connections.length; i++){ - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, equal){ - if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(equal || score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && (score1 >= score2 || equal)){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1 || equal){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(options.network || new Network(this.input, this.output)); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - var elitists = []; - for(var i = 0; i < this.elitism; i++){ - elitists.push(this.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - for(var i = 0; i < elitists.length; i++){ - this.population.push(elitists[i]); - } - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = 0; i < this.population.length; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - if(this.clear) genome.clear(); - var score = this.fitness(genome); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.population.length; i++){ - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.population.length; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = (x > 0 ? x : alpha * Math.exp(x) - alpha) * scale; - if(derivate) - return x > 0 ? scale : fx + alpha; - return fx; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES" - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.30/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.30/neataptic.min.js deleted file mode 100644 index f2faa70..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.30/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.neataptic=n():t.neataptic=n()}(this,function(){return function(t){function n(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return t[e].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var o={};return n.m=t,n.c=o,n.i=function(t){return t},n.d=function(t,o,e){n.o(t,o)||Object.defineProperty(t,o,{configurable:!1,enumerable:!0,get:e})},n.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(o,"a",o),o},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="",n(n.s=18)}([function(t,n){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,n,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(n,e))&&(t.exports=i),void 0!==t&&t.exports&&(t.exports=s),"object"==typeof window&&(!function(){var t=window.methods;s.ninja=function(){return window.methods=t,s}}(),window.methods=s)},function(t,n,o){(function(t){function n(t){this.bias="input"==t?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=t||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaBias=0,this.totalDeltaBias=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}t&&(t.exports=n);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;n.prototype={activate:function(t){if(void 0!==t)return this.activation=t,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var n=0;n-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var n=0;n-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*c:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*c))}}return this.activation},propagate:function(t,n,o,e){n=n||0,t=t||.3;var i=0;if("output"==this.type)this.error.responsibility=this.error.projected=e-this.activation;else{for(var s=0;s=0;n--){var o=t[n],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,a){var h=[];if(t instanceof n){if(void 0===o&&(this!=t?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var c=0;c=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[e]&&a.to==t.nodes[s]){this.connections.out.splice(r,1);break}}if(o)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[s]&&a.to==this.nodes[e]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var e=0;e=0;s--){var a=this.connections.out[s];if(a.from==this.nodes[e]&&a.to==t){this.connections.out.splice(s,1);break}}if(o)for(var s=this.connections.in.length-1;s>=0;s--){var a=this.connections.in[s];if(a.from==t&&a.to==this.nodes[e]){this.connections.in.splice(s,1);break}}}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,e){if(t instanceof s||t instanceof i)var r=this.output.connect(t,o,e);else if(t instanceof n)var r=t.input(this,o,e);return r},gate:function(t,n){this.output.gate(t,n)},set:function(t){for(var n=0;n=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[o]&&a.to==t.nodes[e]){this.connections.out.splice(r,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[e]&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var o=0;o=0;e--){var a=this.connections.out[e];if(a.from==this.nodes[o]&&a.to==t){this.connections.out.splice(e,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}},clear:function(){for(var t=0;t=this.nodes.length-this.output;s--)this.nodes[s].propagate(t,n,o,e[--i]);for(var s=this.nodes.length-this.output-1;s>=this.input;s--)this.nodes[s].propagate(t,n,o)},clear:function(){for(var t=0;t=0;i--){var r=t.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,t)}for(var a=[],i=t.connections.out.length-1;i>=0;i--){var r=t.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),a.push(r.to),this.disconnect(t,r.to)}for(var h=[],i=0;i=0;i--){var f=t.connections.gated[i];this.ungate(f)}this.disconnect(t,t),this.nodes.splice(n,1)},mutate:function(t){if(void 0===t)throw new Error("No (correct) mutate method given!");switch(t){case h.ADD_NODE:var n=this.connections[Math.floor(Math.random()*this.connections.length)],o=n.gater;this.disconnect(n.from,n.to);var i=this.nodes.indexOf(n.to),s=new e("hidden",this.nodes.length);s.mutate(h.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var c=this.connect(n.from,s)[0],u=this.connect(s,n.to)[0];null!=o&&this.gate(o,Math.random()>=.5?c:u);break;case h.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var l=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[l]);break;case h.ADD_CONN:for(var f=[],p=0;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.to)>this.nodes.indexOf(w.from)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.MOD_WEIGHT:var n=this.connections[Math.floor(Math.random()*this.connections.length)],A=Math.random()*(t.max-t.min)+t.min;n.weight+=A;break;case h.MOD_BIAS:var l=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[l];s.mutate(t);break;case h.MOD_ACTIVATION:if(!t.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var l=Math.floor(Math.random()*(this.nodes.length-(t.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[l];s.mutate(t);break;case h.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.from)>this.nodes.indexOf(w.to)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.SWAP_NODES:var l=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),d=this.nodes[l],l=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),v=this.nodes[l],T=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=T,v.squash=M}},train:function(t,n){n=n||{},void 0===n.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===n.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=n.log||!1,i=n.error||.05,a=n.cost||s.Cost.MSE,h=n.rate||.3,c=n.shuffle||!1,u=n.iterations||0,l=n.crossValidate||!1,f=n.clear||!1,p=n.dropout||0,d=n.momentum||0,g=n.batchSize||1,v=n.ratePolicy||s.Rate.FIXED(),m=n.schedule;if(g>t.length)throw new Error("Batch size must be smaller or equal to dataset length!");if(void 0===n.iterations&&void 0===n.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===n.error&&(i=-1),this.dropout=p,l)var O=n.crossValidate.testSize,w=n.crossValidate.testError,_=Math.ceil((1-O)*t.length),A=t.slice(0,_),N=t.slice(_);for(var L=h,T=0,M=1;M>i&&(0==u||Tv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"error",O.score,"cost error",g),f&&d.generation%f.iterations==0&&f.function({error:g,iteration:d.generation})}l&&m.clear();var w={error:v,generations:d.generation,time:Date.now()-p};return null!=m&&(this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns),w}},n.fromJSON=function(t){var o=new n(t.input,t.output);o.dropout=t.dropout,o.nodes=[],o.connections=[];for(var i=0;i=0;e--)o.nodes.splice(e,1);for(var e=t.nodes.length-t.output;eh)var l=t.nodes.length;else var l=o.nodes.length;for(var f=t.output,p=0;p=.5?t.nodes[p]:o.nodes[p],v=d<.5?t.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=t.nodes[t.nodes.length+p-l];else var g=o.nodes[o.nodes.length+p-l];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var L=!1,T=w.length-1;T>=0;T--)if(O[p].from==w[T].from&&O[p].to==w[T].to){var _=Math.random()>=.5?O[p]:w[T];N.push(_),w[T]=[-1,-1];var L=!0;break}!L&&(a>=h||s)&&N.push(O[p])}if(h>=a||s)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,l.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(l),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),c.push(p),c.push(d),c.push(g),c.push(v),l!=h.length-1&&c.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),c.push(o),a.Construct(c)},GRU:function(){var t=Array.prototype.slice.call(arguments);if(t.length<3)throw new Error("not enough layers (minimum 3) !!");var n=new s(t.shift()),o=new s(t.pop()),e=t,i=[];i.push(n);for(var h=n,c=0;cthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],e=0;e0?1:0},RELU:function(t,n){return n?t>0?1:0:t>0?t:0},SOFTSIGN:function(t,n){var o=1+Math.abs(t);return n?t/Math.pow(o,2):t/o},SINUSOID:function(t,n){return n?Math.cos(t):Math.sin(t)},GAUSSIAN:function(t,n){var o=Math.exp(-Math.pow(t,2));return n?-2*t*o:o},BENT_IDENTITY:function(t,n){var o=Math.sqrt(Math.pow(t,2)+1);return n?t/(2*o)+1:(o-1)/2+t},BIPOLAR:function(t,n){return n?0:t>0?1:-1},BIPOLAR_SIGMOID:function(t,n){var o=2/(1+Math.exp(-t))-1;return n?.5*(1+o)*(1-o):o},HARD_TANH:function(t,n){return n?t>-1&&t<1?1:0:Math.max(-1,Math.min(1,t))},ABSOLUTE:function(t,n){return n?t<0?-1:1:Math.abs(t)},INVERSE:function(t,n){return n?-1:1-t},SELU:function(t,n){var o=1.6732632423543772,e=1.0507009873554805,i=(t>0?t:o*Math.exp(t)-o)*e;return n?t>0?e:i+o:i}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={CROSS_ENTROPY:function(t,n){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if(update){ - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if(update){ - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: false -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.out.length; j++){ - var conn = node.connections.out[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - if(typeof values.bias != 'undefined'){ - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var j = this.connections.in.length - 1; j >= 0; j--){ - var conn = this.connections.in[j]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var i = 0; i < layer.nodes.length; i++){ - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, update, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var i = 0; i < inputs.length; i++){ - var input = inputs[i]; - for(var j = 0; j < outputs.length; j++){ - var output = outputs[j]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var i = 0; i < gaters.length; i++){ - if(connections.length == 0) break; - var gater = gaters[i]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var i = 0; i < allconnections.length; i++){ - var conn = allconnections[i]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if(( method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)){ - if(Config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(batchSize > set.length) throw new Error("Batch size must be smaller or equal to dataset length!") - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for(var i = 0; i < set.length; i++){ - var input = set[i].input; - var target = set[i].output; - - var update = (i+1) % batchSize == 0 || (i+1) == set.length ? true : false; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for(var i = 0; i < set.length; i++){ - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - var tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - options = options || {}; - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitnessFunction(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitnessFunction, options); - - var fitness = -Infinity; - var bestFitness = -Infinity; - var bestGenome = null; - - while(fitness < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - var fitness = fittest.score; - var error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if(fitness > bestFitness){ - bestFitness = fitness; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'fitness', fitness, 'error', -error); - } - - if(schedule && neat.generation % schedule.iterations == 0){ - schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestFitness, - generations: neat.generation, - time: Date.now() - start - }; - - if(bestGenome != null){ - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - } - - return results; - }, -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(var i = 0; i < json.nodes.length; i++){ - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for(var i = 0; i < json.connections.length; i++){ - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, equal){ - if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(equal || score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && (score1 >= score2 || equal)){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1 || equal){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - this.template = options.network || new Network(this.input, this.output) - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - var elitists = []; - for(var i = 0; i < this.elitism; i++){ - elitists.push(this.population[i]); - } - - // Provenance - for(var i = 0; i < this.provenance; i++){ - newPopulation.push(Network.fromJSON(this.template.toJSON())) - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism - this.provenance; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - for(var i = 0; i < elitists.length; i++){ - this.population.push(elitists[i]); - } - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = 0; i < this.population.length; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - if(this.clear) genome.clear(); - var score = this.fitness(genome); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.population.length; i++){ - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.population.length; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if(derivate) - return x > 0 ? scale : (fx + alpha) * scale; - return fx * scale; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES", - mutateOutput: true - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN, - Mutation.SWAP_NODES -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.SWAP_NODES -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.31/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.31/neataptic.min.js deleted file mode 100644 index abb40ff..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.31/neataptic.min.js +++ /dev/null @@ -1,27 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -!function(t,n){"object"==typeof exports&&"object"==typeof module?module.exports=n():"function"==typeof define&&define.amd?define([],n):"object"==typeof exports?exports.neataptic=n():t.neataptic=n()}(this,function(){return function(t){function n(e){if(o[e])return o[e].exports;var i=o[e]={i:e,l:!1,exports:{}};return t[e].call(i.exports,i,i.exports,n),i.l=!0,i.exports}var o={};return n.m=t,n.c=o,n.i=function(t){return t},n.d=function(t,o,e){n.o(t,o)||Object.defineProperty(t,o,{configurable:!1,enumerable:!0,get:e})},n.n=function(t){var o=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(o,"a",o),o},n.o=function(t,n){return Object.prototype.hasOwnProperty.call(t,n)},n.p="",n(n.s=18)}([function(t,n){t.exports=function(t){return t.webpackPolyfill||(t.deprecate=function(){},t.paths=[],t.children||(t.children=[]),Object.defineProperty(t,"loaded",{enumerable:!0,get:function(){return t.l}}),Object.defineProperty(t,"id",{enumerable:!0,get:function(){return t.i}}),t.webpackPolyfill=1),t}},function(t,n,o){var e,i,s={Activation:o(10),Mutation:o(15),Selection:o(17),Crossover:o(13),Cost:o(12),Gating:o(14),Connection:o(11),Rate:o(16)};e=[],void 0!==(i=function(){return s}.apply(n,e))&&(t.exports=i),void 0!==t&&t.exports&&(t.exports=s),"object"==typeof window&&(!function(){var t=window.methods;s.ninja=function(){return window.methods=t,s}}(),window.methods=s)},function(t,n,o){(function(t){function n(t){this.bias="input"==t?0:.2*Math.random()-.1,this.squash=r.LOGISTIC,this.type=t||"hidden",this.activation=0,this.state=0,this.old=0,this.mask=1,this.previousDeltaBias=0,this.totalDeltaBias=0,this.connections={in:[],out:[],gated:[],self:new e(this,this,0)},this.error={responsibility:0,projected:0,gated:0}}t&&(t.exports=n);var e=o(4),i=o(1),s=(o(5),o(3)),r=i.Activation,a=i.Mutation;n.prototype={activate:function(t){if(void 0!==t)return this.activation=t,this.activation;this.old=this.state,this.state=this.connections.self.gain*this.connections.self.weight*this.state+this.bias;for(var n=0;n-1?i[a]+=s.weight*s.from.activation:(e.push(r),i.push(s.weight*s.from.activation+(r.connections.self.gater==this?r.old:0))),s.gain=this.activation}for(var n=0;n-1?o.xtrace.values[a]=r.connections.self.gain*r.connections.self.weight*o.xtrace.values[a]+this.derivative*o.elegibility*c:(o.xtrace.nodes.push(r),o.xtrace.values.push(this.derivative*o.elegibility*c))}}return this.activation},propagate:function(t,n,o,e){n=n||0,t=t||.3;var i=0;if("output"==this.type)this.error.responsibility=this.error.projected=e-this.activation;else{for(var s=0;s=0;n--){var o=t[n],e=this.connections.gated.indexOf(o);this.connections.gated.splice(e,1),o.gater=null}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,a){var h=[];if(t instanceof n){if(void 0===o&&(this!=t?(s.warnings&&console.warn("No group connection specified, using ALL_TO_ALL"),o=e.Connection.ALL_TO_ALL):(s.warnings&&console.warn("No group connection specified, using ONE_TO_ONE"),o=e.Connection.ONE_TO_ONE)),o==e.Connection.ALL_TO_ALL||o==e.Connection.ALL_TO_ELSE){for(var c=0;c=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[e]&&a.to==t.nodes[s]){this.connections.out.splice(r,1);break}}if(o)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[s]&&a.to==this.nodes[e]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var e=0;e=0;s--){var a=this.connections.out[s];if(a.from==this.nodes[e]&&a.to==t){this.connections.out.splice(s,1);break}}if(o)for(var s=this.connections.in.length-1;s>=0;s--){var a=this.connections.in[s];if(a.from==t&&a.to==this.nodes[e]){this.connections.in.splice(s,1);break}}}},clear:function(){for(var t=0;t=0;e--)void 0===o?this.nodes[e].propagate(t,n):this.nodes[e].propagate(t,n,o[e])},connect:function(t,o,e){if(t instanceof s||t instanceof i)var r=this.output.connect(t,o,e);else if(t instanceof n)var r=t.input(this,o,e);return r},gate:function(t,n){this.output.gate(t,n)},set:function(t){for(var n=0;n=0;r--){var a=this.connections.out[r];if(a.from==this.nodes[o]&&a.to==t.nodes[e]){this.connections.out.splice(r,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t.nodes[e]&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}else if(t instanceof i)for(var o=0;o=0;e--){var a=this.connections.out[e];if(a.from==this.nodes[o]&&a.to==t){this.connections.out.splice(e,1);break}}if(n)for(var r=this.connections.in.length-1;r>=0;r--){var a=this.connections.in[r];if(a.from==t&&a.to==this.nodes[o]){this.connections.in.splice(r,1);break}}}},clear:function(){for(var t=0;t=this.nodes.length-this.output;s--)this.nodes[s].propagate(t,n,o,e[--i]);for(var s=this.nodes.length-this.output-1;s>=this.input;s--)this.nodes[s].propagate(t,n,o)},clear:function(){for(var t=0;t=0;i--){var r=t.connections.in[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),e.push(r.from),this.disconnect(r.from,t)}for(var a=[],i=t.connections.out.length-1;i>=0;i--){var r=t.connections.out[i];s.Mutation.SUB_NODE.keep_gates&&null!=r.gater&&r.gater!=t&&o.push(r.gater),a.push(r.to),this.disconnect(t,r.to)}for(var h=[],i=0;i=0;i--){var f=t.connections.gated[i];this.ungate(f)}this.disconnect(t,t),this.nodes.splice(n,1)},mutate:function(t){if(void 0===t)throw new Error("No (correct) mutate method given!");switch(t){case h.ADD_NODE:var n=this.connections[Math.floor(Math.random()*this.connections.length)],o=n.gater;this.disconnect(n.from,n.to);var i=this.nodes.indexOf(n.to),s=new e("hidden",this.nodes.length);s.mutate(h.MOD_ACTIVATION);var a=Math.min(i,this.nodes.length-this.output);this.nodes.splice(a,0,s);var c=this.connect(n.from,s)[0],u=this.connect(s,n.to)[0];null!=o&&this.gate(o,Math.random()>=.5?c:u);break;case h.SUB_NODE:if(this.nodes.length==this.input+this.output){r.warnings&&console.warn("No more nodes left to remove!");break}var l=Math.floor(Math.random()*(this.nodes.length-this.output-this.input)+this.input);this.remove(this.nodes[l]);break;case h.ADD_CONN:for(var f=[],p=0;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.to)>this.nodes.indexOf(w.from)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.MOD_WEIGHT:var n=this.connections[Math.floor(Math.random()*this.connections.length)],A=Math.random()*(t.max-t.min)+t.min;n.weight+=A;break;case h.MOD_BIAS:var l=Math.floor(Math.random()*(this.nodes.length-this.input)+this.input),s=this.nodes[l];s.mutate(t);break;case h.MOD_ACTIVATION:if(!t.mutateOutput&&this.input+this.output==this.nodes.length){r.warnings&&console.warn("No nodes that allow mutation of activation function");break}var l=Math.floor(Math.random()*(this.nodes.length-(t.mutateOutput?0:this.output)-this.input)+this.input),s=this.nodes[l];s.mutate(t);break;case h.ADD_SELF_CONN:for(var O=[],p=this.input;p1&&w.to.connections.in.length>1&&this.nodes.indexOf(w.from)>this.nodes.indexOf(w.to)&&O.push(w)}if(0==O.length){r.warnings&&console.warn("No connections to remove!");break}var _=O[Math.floor(Math.random()*O.length)];this.disconnect(_.from,_.to);break;case h.SWAP_NODES:if(t.mutateOutput&&this.nodes.length-this.input<2||!t.mutateOutput&&this.nodes.length-this.input-this.output<2){r.warnings&&console.warn("No nodes that allow swapping of bias and activation function");break}var l=Math.floor(Math.random()*(this.nodes.length-(t.mutateOutput?0:this.output)-this.input)+this.input),d=this.nodes[l],l=Math.floor(Math.random()*(this.nodes.length-(t.mutateOutput?0:this.output)-this.input)+this.input),v=this.nodes[l],T=d.bias,M=d.squash;d.bias=v.bias,d.squash=v.squash,v.bias=T,v.squash=M}},train:function(t,n){n=n||{},void 0===n.rate&&r.warnings&&console.warn("Using default learning rate, please define a rate!"),void 0===n.iterations&&r.warnings&&console.warn("No target iterations given, running until error is reached!");var o=Date.now(),e=n.log||!1,i=n.error||.05,a=n.cost||s.Cost.MSE,h=n.rate||.3,c=n.shuffle||!1,u=n.iterations||0,l=n.crossValidate||!1,f=n.clear||!1,p=n.dropout||0,d=n.momentum||0,g=n.batchSize||1,v=n.ratePolicy||s.Rate.FIXED(),m=n.schedule;if(g>t.length)throw new Error("Batch size must be smaller or equal to dataset length!");if(void 0===n.iterations&&void 0===n.error?r.warnings&&console.warn("At least one of the following options must be specified: error, iterations"):void 0===n.error&&(i=-1),this.dropout=p,l)var O=n.crossValidate.testSize,w=n.crossValidate.testError,_=Math.ceil((1-O)*t.length),A=t.slice(0,_),N=t.slice(_);for(var L=h,T=0,M=1;M>i&&(0==u||Tv&&(v=g,m=O),u&&d.generation%u==0&&console.log("generation",d.generation,"fitness",g,"error",-w),f&&d.generation%f.iterations==0&&f.function({fitness:g,error:-w,iteration:d.generation})}l&&m.clear();var _={error:v,generations:d.generation,time:Date.now()-p};return null!=m&&(this.nodes=m.nodes,this.connections=m.connections,this.gates=m.gates,this.selfconns=m.selfconns),_}},n.fromJSON=function(t){var o=new n(t.input,t.output);o.dropout=t.dropout,o.nodes=[],o.connections=[];for(var i=0;i=0;e--)o.nodes.splice(e,1);for(var e=t.nodes.length-t.output;eh)var l=t.nodes.length;else var l=o.nodes.length;for(var f=t.output,p=0;p=.5?t.nodes[p]:o.nodes[p],v=d<.5?t.nodes[p]:o.nodes[p];void 0!==g&&"output"!=g.type||(g=v)}else if(Math.random()>=.5)var g=t.nodes[t.nodes.length+p-l];else var g=o.nodes[o.nodes.length+p-l];var m=new e;m.bias=g.bias,m.squash=g.squash,m.type=g.type,r.nodes.push(m)}for(var O=[],w=[],p=0;p=0;p--){for(var L=!1,T=w.length-1;T>=0;T--)if(O[p].from==w[T].from&&O[p].to==w[T].to){var _=Math.random()>=.5?O[p]:w[T];N.push(_),w[T]=[-1,-1];var L=!0;break}!L&&(a>=h||s)&&N.push(O[p])}if(h>=a||s)for(var p=0;p=0;a--)"output"==e[a].type||e[a].connections.out.length+e[a].connections.gated.length==0?(e[a].type="output",o.output++,l.push(e[a]),e.splice(a,1)):"input"!=e[a].type&&e[a].connections.in.length||(e[a].type="input",o.input++,u.push(e[a]),e.splice(a,1));if(e=u.concat(e).concat(l),0==o.input||0==o.output)throw new Error("Given nodes have no clear input/output node!");for(var a=0;a0){var O=r.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}if(i.memoryToMemory){var O=g.connect(g,e.Connection.ALL_TO_ELSE);p.gate(O,e.Gating.INPUT)}if(i.outputToMemory){var O=o.connect(g,e.Connection.ALL_TO_ALL);p.gate(O,e.Gating.INPUT)}i.outputToGates&&(o.connect(p,e.Connection.ALL_TO_ALL),o.connect(d,e.Connection.ALL_TO_ALL),o.connect(v,e.Connection.ALL_TO_ALL)),c.push(p),c.push(d),c.push(g),c.push(v),l!=h.length-1&&c.push(m),u=m}return i.inputToOutput&&r.connect(o,e.Connection.ALL_TO_ALL),c.push(o),a.Construct(c)},GRU:function(){var t=Array.prototype.slice.call(arguments);if(t.length<3)throw new Error("not enough layers (minimum 3) !!");var n=new s(t.shift()),o=new s(t.pop()),e=t,i=[];i.push(n);for(var h=n,c=0;cthis.popsize)throw new Error("Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size");for(var c=[],e=0;e0?1:0},RELU:function(t,n){return n?t>0?1:0:t>0?t:0},SOFTSIGN:function(t,n){var o=1+Math.abs(t);return n?t/Math.pow(o,2):t/o},SINUSOID:function(t,n){return n?Math.cos(t):Math.sin(t)},GAUSSIAN:function(t,n){var o=Math.exp(-Math.pow(t,2));return n?-2*t*o:o},BENT_IDENTITY:function(t,n){var o=Math.sqrt(Math.pow(t,2)+1);return n?t/(2*o)+1:(o-1)/2+t},BIPOLAR:function(t,n){return n?0:t>0?1:-1},BIPOLAR_SIGMOID:function(t,n){var o=2/(1+Math.exp(-t))-1;return n?.5*(1+o)*(1-o):o},HARD_TANH:function(t,n){return n?t>-1&&t<1?1:0:Math.max(-1,Math.min(1,t))},ABSOLUTE:function(t,n){return n?t<0?-1:1:Math.abs(t)},INVERSE:function(t,n){return n?-1:1-t},SELU:function(t,n){var o=1.6732632423543772,e=1.0507009873554805,i=t>0?t:o*Math.exp(t)-o;return n?t>0?e:(i+o)*e:i*e}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={ALL_TO_ALL:{name:"OUTPUT"},ALL_TO_ELSE:{name:"INPUT"},ONE_TO_ONE:{name:"SELF"}};t&&(t.exports=n)}).call(n,o(0)(t))},function(t,n,o){(function(t){var n={CROSS_ENTROPY:function(t,n){for(var o=0,e=0;e. Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if(update){ - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if(update){ - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: false -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.out.length; j++){ - var conn = node.connections.out[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - if(typeof values.bias != 'undefined'){ - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var j = this.connections.in.length - 1; j >= 0; j--){ - var conn = this.connections.in[j]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var i = 0; i < layer.nodes.length; i++){ - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, update, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var i = 0; i < inputs.length; i++){ - var input = inputs[i]; - for(var j = 0; j < outputs.length; j++){ - var output = outputs[j]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var i = 0; i < gaters.length; i++){ - if(connections.length == 0) break; - var gater = gaters[i]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var i = 0; i < allconnections.length; i++){ - var conn = allconnections[i]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if(( method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)){ - if(Config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(batchSize > set.length) throw new Error("Batch size must be smaller or equal to dataset length!") - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for(var i = 0; i < set.length; i++){ - var input = set[i].input; - var target = set[i].output; - - var update = (i+1) % batchSize == 0 || (i+1) == set.length ? true : false; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for(var i = 0; i < set.length; i++){ - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - var tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - options = options || {}; - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitnessFunction(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitnessFunction, options); - - var fitness = -Infinity; - var bestFitness = -Infinity; - var bestGenome = null; - - while(fitness < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - var fitness = fittest.score; - var error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if(fitness > bestFitness){ - bestFitness = fitness; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'fitness', fitness, 'error', -error); - } - - if(schedule && neat.generation % schedule.iterations == 0){ - schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestFitness, - generations: neat.generation, - time: Date.now() - start - }; - - if(bestGenome != null){ - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - } - - return results; - }, - - standalone: function(){ - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - for(var i = 0; i < this.input; i++){ - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var line = `A[${i}] = input[${i}];`; - lines.push(line); - } - - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if(present.indexOf(node.squash.name) == -1){ - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - var index = this.nodes.indexOf(conn.from); - var computation = `A[${index}] * ${conn.weight}`; - - if(conn.gater != null){ - var gaterIndex = this.nodes.indexOf(conn.gater) - computation += ` * A[${gaterIndex}]`; - } - - incoming.push(computation); - } - - if(node.connections.self.weight){ - var conn = node.connections.self; - var computation = `S[${i}] * ${conn.weight}`; - - if(conn.gater != null){ - var gaterIndex = this.nodes.indexOf(conn.gater) - computation += ` * A[${gaterIndex}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for(var i = this.nodes.length - this.output; i < this.nodes.length; i++){ - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join("\r\n")}\r\n}`; - - return total; - } -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(var i = 0; i < json.nodes.length; i++){ - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for(var i = 0; i < json.connections.length; i++){ - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, equal){ - if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(equal || score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && (score1 >= score2 || equal)){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1 || equal){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - this.template = options.network || new Network(this.input, this.output) - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - var elitists = []; - for(var i = 0; i < this.elitism; i++){ - elitists.push(this.population[i]); - } - - // Provenance - for(var i = 0; i < this.provenance; i++){ - newPopulation.push(Network.fromJSON(this.template.toJSON())) - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism - this.provenance; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - for(var i = 0; i < elitists.length; i++){ - this.population.push(elitists[i]); - } - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = 0; i < this.population.length; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - if(this.clear) genome.clear(); - var score = this.fitness(genome); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.population.length; i++){ - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.population.length; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if(derivate) - return x > 0 ? scale : (fx + alpha) * scale; - return fx * scale; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES", - mutateOutput: true - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN, - Mutation.SWAP_NODES -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.SWAP_NODES -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.32/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.32/neataptic.min.js deleted file mode 100644 index d584acd..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.32/neataptic.min.js +++ /dev/null @@ -1,3602 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if(update){ - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if(update){ - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: false -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.out.length; j++){ - var conn = node.connections.out[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - if(typeof values.bias != 'undefined'){ - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var j = this.connections.in.length - 1; j >= 0; j--){ - var conn = this.connections.in[j]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var i = 0; i < layer.nodes.length; i++){ - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, update, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var i = 0; i < inputs.length; i++){ - var input = inputs[i]; - for(var j = 0; j < outputs.length; j++){ - var output = outputs[j]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var i = 0; i < gaters.length; i++){ - if(connections.length == 0) break; - var gater = gaters[i]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var i = 0; i < allconnections.length; i++){ - var conn = allconnections[i]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if(( method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)){ - if(Config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(batchSize > set.length) throw new Error("Batch size must be smaller or equal to dataset length!") - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for(var i = 0; i < set.length; i++){ - var input = set[i].input; - var target = set[i].output; - - var update = (i+1) % batchSize == 0 || (i+1) == set.length ? true : false; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var input, output, target; - - var start = Date.now(); - - for(var i = 0; i < set.length; i++){ - input = set[i].input; - target = set[i].output; - output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - var tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? this.nodes.indexOf(node.connections.self.gater) : null; - json.connections.push(tojson); - } - } - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - var tojson = conn.toJSON(); - tojson.from = this.nodes.indexOf(conn.from); - tojson.to = this.nodes.indexOf(conn.to); - - tojson.gater = conn.gater != null ? this.nodes.indexOf(conn.gater) : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - options = options || {}; - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitnessFunction(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitnessFunction, options); - - var fitness = -Infinity; - var bestFitness = -Infinity; - var bestGenome = null; - - while(fitness < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - var fitness = fittest.score; - var error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if(fitness > bestFitness){ - bestFitness = fitness; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'fitness', fitness, 'error', -error); - } - - if(schedule && neat.generation % schedule.iterations == 0){ - schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestFitness, - generations: neat.generation, - time: Date.now() - start - }; - - if(bestGenome != null){ - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - } - - return results; - }, - - standalone: function(){ - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - for(var i = 0; i < this.input; i++){ - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var line = `A[${i}] = input[${i}];`; - lines.push(line); - } - - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if(present.indexOf(node.squash.name) == -1){ - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - var index = this.nodes.indexOf(conn.from); - var computation = `A[${index}] * ${conn.weight}`; - - if(conn.gater != null){ - var gaterIndex = this.nodes.indexOf(conn.gater) - computation += ` * A[${gaterIndex}]`; - } - - incoming.push(computation); - } - - if(node.connections.self.weight){ - var conn = node.connections.self; - var computation = `S[${i}] * ${conn.weight}`; - - if(conn.gater != null){ - var gaterIndex = this.nodes.indexOf(conn.gater) - computation += ` * A[${gaterIndex}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for(var i = this.nodes.length - this.output; i < this.nodes.length; i++){ - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join("\r\n")}\r\n}`; - - return total; - } -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(var i = 0; i < json.nodes.length; i++){ - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for(var i = 0; i < json.connections.length; i++){ - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, equal){ - if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(equal || score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && (score1 >= score2 || equal)){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1 || equal){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - this.template = options.network || new Network(this.input, this.output) - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - var copy = Network.fromJSON(network.toJSON()); - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - var elitists = []; - for(var i = 0; i < this.elitism; i++){ - elitists.push(this.population[i]); - } - - // Provenance - for(var i = 0; i < this.provenance; i++){ - newPopulation.push(Network.fromJSON(this.template.toJSON())) - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism - this.provenance; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - for(var i = 0; i < elitists.length; i++){ - this.population.push(elitists[i]); - } - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = 0; i < this.population.length; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - if(this.clear) genome.clear(); - var score = this.fitness(genome); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.population.length; i++){ - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.population.length; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if(derivate) - return x > 0 ? scale : (fx + alpha) * scale; - return fx * scale; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES", - mutateOutput: true - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN, - Mutation.SWAP_NODES -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.SWAP_NODES -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.33/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.33/neataptic.js deleted file mode 100644 index f585389..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.33/neataptic.js +++ /dev/null @@ -1,3614 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if(update){ - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if(update){ - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: false -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.out.length; j++){ - var conn = node.connections.out[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - if(typeof values.bias != 'undefined'){ - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var j = this.connections.in.length - 1; j >= 0; j--){ - var conn = this.connections.in[j]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var i = 0; i < layer.nodes.length; i++){ - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, update, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var i = 0; i < inputs.length; i++){ - var input = inputs[i]; - for(var j = 0; j < outputs.length; j++){ - var output = outputs[j]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var i = 0; i < gaters.length; i++){ - if(connections.length == 0) break; - var gater = gaters[i]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var i = 0; i < allconnections.length; i++){ - var conn = allconnections[i]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if(( method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)){ - if(Config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(batchSize > set.length) throw new Error("Batch size must be smaller or equal to dataset length!") - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for(var i = 0; i < set.length; i++){ - var input = set[i].input; - var target = set[i].output; - - var update = (i+1) % batchSize == 0 || (i+1) == set.length ? true : false; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var start = Date.now(); - - for(var i = 0; i < set.length; i++){ - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].index = i; - } - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - var tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - var tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - options = options || {}; - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitnessFunction(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitnessFunction, options); - - var fitness = -Infinity; - var bestFitness = -Infinity; - var bestGenome = null; - - while(fitness < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - var fitness = fittest.score; - var error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if(fitness > bestFitness){ - bestFitness = fitness; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'fitness', fitness, 'error', -error); - } - - if(schedule && neat.generation % schedule.iterations == 0){ - schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestFitness, - generations: neat.generation, - time: Date.now() - start - }; - - if(bestGenome != null){ - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - } - - return results; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function(){ - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - for(var i = 0; i < this.input; i++){ - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];') - - // So we don't have to use expensive .indexOf() - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].index = i; - } - - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if(present.indexOf(node.squash.name) == -1){ - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if(conn.gater != null){ - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if(node.connections.self.weight){ - var conn = node.connections.self; - var computation = `S[${i}] * ${conn.weight}`; - - if(conn.gater != null){ - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for(var i = this.nodes.length - this.output; i < this.nodes.length; i++){ - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join("\r\n")}\r\n}`; - - return total; - } -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(var i = 0; i < json.nodes.length; i++){ - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for(var i = 0; i < json.connections.length; i++){ - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, equal){ - if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(equal || score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && (score1 >= score2 || equal)){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1 || equal){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - if(this.template){ - var copy = Network.fromJSON(network.toJSON()); - } else { - var copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - var elitists = []; - for(var i = 0; i < this.elitism; i++){ - elitists.push(this.population[i]); - } - - // Provenance - for(var i = 0; i < this.provenance; i++){ - newPopulation.push(Network.fromJSON(this.template.toJSON())) - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism - this.provenance; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - for(var i = 0; i < elitists.length; i++){ - this.population.push(elitists[i]); - } - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = 0; i < this.population.length; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - if(this.clear) genome.clear(); - var score = this.fitness(genome); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.population.length; i++){ - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.population.length; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if(derivate) - return x > 0 ? scale : (fx + alpha) * scale; - return fx * scale; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES", - mutateOutput: true - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN, - Mutation.SWAP_NODES -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.SWAP_NODES -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.33/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.33/neataptic.min.js deleted file mode 100644 index f585389..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.33/neataptic.min.js +++ /dev/null @@ -1,3614 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 18); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports) { - -module.exports = function(module) { - if(!module.webpackPolyfill) { - module.deprecate = function() {}; - module.paths = []; - // module.parent = undefined by default - if(!module.children) module.children = []; - Object.defineProperty(module, "loaded", { - enumerable: true, - get: function() { - return module.l; - } - }); - Object.defineProperty(module, "id", { - enumerable: true, - get: function() { - return module.i; - } - }); - module.webpackPolyfill = 1; - } - return module; -}; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation : __webpack_require__(10), - Mutation : __webpack_require__(15), - Selection : __webpack_require__(17), - Crossover : __webpack_require__(13), - Cost : __webpack_require__(12), - Gating : __webpack_require__(14), - Connection : __webpack_require__(11), - Rate : __webpack_require__(16) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Methods }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Methods; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var oldMethods = window['methods']; - Methods.ninja = function(){ - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Node; - -/* Import */ -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Group = __webpack_require__(5); -var Config = __webpack_require__(3); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node(type) { - this.bias = (type == 'input') ? 0 : Math.random() * .2 - .1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in : [], - out : [], - gated : [], - self : new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function(input){ - // Check if an input is given - if (typeof input != 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - for(var i = 0; i < this.connections.in.length; i++){ - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - - var index = nodes.indexOf(node); - if(index > -1){ - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater == this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for(var j = 0; j < nodes.length; j++){ - var node = nodes[j]; - var influence = influences[j]; - - var index = connection.xtrace.nodes.indexOf(node); - - if(index >-1){ - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function(rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || .3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type == 'output'){ - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - for(var i = 0; i < this.connections.out.length; i++) { - var connection = this.connections.out[i]; - var node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for(var i = 0; i < this.connections.gated.length; i++){ - var conn = this.connections.gated[i]; - var node = conn.to; - var influence = node.connections.self.gater == this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if(this.type == 'constant') return; - - // Adjust all the node's incoming connections - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - var gradient = this.error.projected * connection.elegibility; - - for(var j = 0; j < connection.xtrace.nodes.length; j++){ - var node = connection.xtrace.nodes[j]; - var value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - var deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if(update){ - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if(update){ - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function(target, weight){ - var connections = []; - if(typeof target.bias != 'undefined'){ // must be a node! - if(target == this){ - // Turn on the self connection by setting the weight - if(this.connections.self.weight != 0){ - if(Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)){ - throw new Error('Already projecting a connection to this node!'); - } else { - var connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for(var i = 0; i < target.nodes.length; i++){ - var connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function(node, twosided){ - if(this == node){ - this.connections.self.weight = 0; - return; - } - - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - this.connections.out.splice(i, 1); - var j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if(conn.gater != null) this.ungate(conn); - break; - } - } - - if(twosided){ - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function(connections){ - if(!Array.isArray(connections)){ - connections = [connections]; - } - - - for(var i = connections.length - 1; i >= 0; i--){ - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function(){ - for(var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values : [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No mutate method given!'); - } else if(!method.name in Methods.Mutation){ - throw new Error('This method does not exist!'); - } - - switch(method){ - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function(node){ - for(var i = 0; i < this.connections.out.length; i++){ - var conn = this.connections.out[i]; - if(conn.to == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function(node){ - for(var i = 0; i < this.connections.in.length; i++){ - var conn = this.connections.in[i]; - if(conn.from == node){ - return true; - } - } - if(node == this && this.connections.self.weight != 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function(){ - var json = { - bias : this.bias, - type : this.type, - squash : this.squash.name, - mask : this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function(json){ - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for(squash in Activation){ - if(Activation[squash].name == json.squash){ - node.squash = Activation[squash]; - break; - } - } - - return node; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: false -}; - -/* Export */ -if (module) module.exports = Config; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection(from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight == 'undefined') ? Math.random() * .2 - .1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values : [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON : function(){ - var json = { - weight : this.weight - }; - - return json; - } -}; - - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function(a, b) { - return 1/2 * (a + b) * (a + b + 1) + b; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Layer = __webpack_require__(6); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group(size){ - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; - - for(var i = 0; i < size; i++){ - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - var connections = []; - if(target instanceof Group){ - if(typeof method == 'undefined'){ - if(this != target){ - if(Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if(Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if(method == Methods.Connection.ALL_TO_ALL || method == Methods.Connection.ALL_TO_ELSE){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - if(method == Methods.Connection.ALL_TO_ELSE && this.nodes[i] == target.nodes[j]) continue; - var connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(method == Methods.Connection.ONE_TO_ONE){ - if(this.nodes.length != target.nodes.length){ - throw new Error('From and To group must be the same size!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if(target instanceof Layer){ - var connections = target.input(this, method, weight); - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - if(typeof method == 'undefined'){ - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if(!Array.isArray(connections)){ - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(!nodes1.includes(connection.from)) nodes1.push(connection.from); - if(!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch(method){ - case Methods.Gating.INPUT: - for(var i = 0; i < nodes2.length; i++){ - var node = nodes2[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - for(var j = 0; j < node.connections.out.length; j++){ - var conn = node.connections.out[j]; - if(connections.includes(conn)){ - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for(var i = 0; i < nodes1.length; i++){ - var node = nodes1[i]; - var gater = this.nodes[i % this.nodes.length]; - - if(connections.includes(node.connections.self)){ - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - if(typeof values.bias != 'undefined'){ - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var j = this.connections.in.length - 1; j >= 0; j--){ - var conn = this.connections.in[j]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(1); -var Connection = __webpack_require__(4); -var Node = __webpack_require__(2); -var Config = __webpack_require__(3); -var Architect = __webpack_require__(8); -var Group = __webpack_require__(5); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer(){ - this.output = null; - - this.nodes = []; - this.connections = { in : [], out: [] , self: [] }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function(value){ - var values = []; - - if(typeof value != 'undefined' && value.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = 0; i < this.nodes.length; i++){ - if(typeof value == 'undefined'){ - var activation = this.nodes[i].activate(); - } else { - var activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function(rate, momentum, target){ - if(typeof target != 'undefined' && target.length != this.nodes.length){ - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for(var i = this.nodes.length - 1; i >= 0; i--){ - if(typeof target == 'undefined'){ - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function(target, method, weight){ - if(target instanceof Group || target instanceof Node){ - var connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer){ - var connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function(connections, method){ - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node instanceof Node){ - if(typeof values.bias != 'undefined'){ - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if(node instanceof Group){ - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function(target, twosided){ - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - if(target instanceof Group){ - for(var i = 0; i < this.nodes.length; i++){ - for(var j = 0; j < target.nodes.length; j++){ - this.nodes[i].disconnect(target.nodes[j], twosided); - - for(var k = this.connections.out.length - 1; k >= 0; k--){ - var conn = this.connections.out[k]; - - if(conn.from == this.nodes[i] && conn.to == target.nodes[j]){ - this.connections.out.splice(k, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target.nodes[j] && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if(target instanceof Node){ - for(var i = 0; i < this.nodes.length; i++){ - var connection = this.nodes[i].disconnect(target, twosided); - - for(var j = this.connections.out.length - 1; j >= 0; j--){ - var conn = this.connections.out[j]; - - if(conn.from == this.nodes[i] && conn.to == target){ - this.connections.out.splice(j, 1); - break; - } - } - - if(twosided){ - for(var k = this.connections.in.length - 1; k >= 0; k--){ - var conn = this.connections.in[k]; - - if(conn.from == target && conn.to == this.nodes[i]){ - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - } -} - -Layer.Dense = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - } - - return layer; -} - -Layer.LSTM = function(size){ - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - } - - return layer; -}; - -Layer.GRU = function(size){ - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ bias: 0, squash: Methods.Activation.IDENTITY, type: 'constant'}); - memoryCell.set({ squash: Methods.Activation.TANH }); - inverseUpdateGate.set({ bias: 0, squash: Methods.Activation.INVERSE, type: 'constant'}); - updateGate.set({ bias: 1 }); - resetGate.set({ bias: 0 }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - } - - return layer; -} - -Layer.Memory = function(size, memory){ - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - for(var i = 0; i < memory; i++){ - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if(previous != null){ - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for(var i = 0; i < layer.nodes.length; i++){ - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for(var group in layer.nodes){ - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function(from, method, weight){ - if(from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if(from.nodes.length != layer.nodes[layer.nodes.length-1].nodes.length){ - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length-1], Methods.Connection.ONE_TO_ONE, 1); - } - - return layer; -} - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Network; - -/* Import */ -var Node = __webpack_require__(2); -var Connection = __webpack_require__(4); -var Methods = __webpack_require__(1); -var Config = __webpack_require__(3); -var Neat = __webpack_require__(9); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network(input, output){ - if(typeof input == 'undefined' || typeof output == 'undefined'){ - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - for(var i = 0; i < this.input + this.output; i++){ - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for(var i = 0; i < this.input; i++){ - for(var j = this.input; j < this.output + this.input; j++){ - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function(input, training){ - var output = []; - // Activate nodes chronologically - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'input'){ - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type == 'output'){ - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if(training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function(rate, momentum, update, target){ - if(typeof target != 'undefined' && target.length != this.output){ - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - for(var i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--){ - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for(var i = this.nodes.length - this.output - 1; i >= this.input; i--){ - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function(){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function(from, to, weight){ - var connections = from.connect(to, weight); - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(from != to){ - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function(from, to){ - // Delete the connection in the network's connection array - var connections = from == to ? this.selfconns : this.connections; - - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.from == from && connection.to == to){ - if(connection.gater != null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function(node, connection){ - if(this.nodes.indexOf(node) == -1){ - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null){ - if(Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function(connection){ - var index = this.gates.indexOf(connection); - if(index == -1){ - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function(node){ - var index = this.nodes.indexOf(node); - - if(index == -1){ - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for(var i = node.connections.in.length - 1; i >= 0; i--){ - var connection = node.connections.in[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for(var i = node.connections.out.length - 1; i >= 0; i--){ - var connection = node.connections.out[i]; - if(Methods.Mutation.SUB_NODE.keep_gates && connection.gater != null && connection.gater != node){ - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for(var i = 0; i < inputs.length; i++){ - var input = inputs[i]; - for(var j = 0; j < outputs.length; j++){ - var output = outputs[j]; - if(!input.isProjectingTo(output)){ - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for(var i = 0; i < gaters.length; i++){ - if(connections.length == 0) break; - var gater = gaters[i]; - - var connIndex = Math.floor(Math.random() * connections.length); - var conn = connections[connIndex]; - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for(var i = node.connections.gated.length - 1; i >= 0 ; i--){ - var conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function(method){ - if(typeof method == 'undefined'){ - throw new Error('No (correct) mutate method given!'); - } - - switch(method){ - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if(gater != null){ - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if(this.nodes.length == this.input + this.output){ - if(Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for(var i = 0; i < this.nodes.length - this.output; i++){ - var node1 = this.nodes[i]; - for(var j = Math.max(i + 1, this.input); j < this.nodes.length; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if(!method.mutateOutput && this.input + this.output == this.nodes.length){ - if(Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - if(this.selfconns.indexOf(node.connections.self) == -1){ - possible.push(node); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if(this.selfconns.length == 0){ - if(Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for(var i = 0; i < allconnections.length; i++){ - var conn = allconnections[i]; - if(conn.gater == null){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if(this.gates.length == 0){ - if(Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for(var i = this.input; i < this.nodes.length; i++){ - var node1 = this.nodes[i]; - for(var j = this.input; j < i; j++){ - var node2 = this.nodes[j]; - if(!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if(available.length == 0){ - if(Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - // Check if it is not disabling a node - if(conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)){ - possible.push(conn); - } - } - - if(possible.length == 0){ - if(Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if(( method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)){ - if(Config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function(set, options) { - options = options || {}; - - // Warning messages - if(typeof options.rate == 'undefined'){ - if(Config.warnings) console.warn('Using default learning rate, please define a rate!') - } - - if(typeof options.iterations == "undefined"){ - if(Config.warnings) console.warn('No target iterations given, running until error is reached!') - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if(batchSize > set.length) throw new Error("Batch size must be smaller or equal to dataset length!") - - if(typeof options.iterations == 'undefined' && typeof options.error == 'undefined'){ - if(Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if(typeof options.error == 'undefined'){ - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if(crossValidate){ - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - while (error > targetError && ( iterations == 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - error += this.test(testSet, cost).error; - if(clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if(clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if(shuffle){ - for (var j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if(log && iteration % log == 0){ - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if(schedule && iteration % schedule.iterations == 0){ - schedule.function({ error: error, iteration: iteration }); - } - } - - if(clear) this.clear(); - - if(dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function(set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for(var i = 0; i < set.length; i++){ - var input = set[i].input; - var target = set[i].output; - - var update = (i+1) % batchSize == 0 || (i+1) == set.length ? true : false; - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function(set, cost) { - // Check if dropout is enabled, set correct mask - if(this.dropout){ - for(var i = 0; i < this.nodes.length; i++){ - if(this.nodes[i].type == 'hidden' || this.nodes[i].type == 'constant'){ - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var start = Date.now(); - - for(var i = 0; i < set.length; i++){ - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function(width, height){ - var input = 0; - var output = 0; - - var json = { - nodes : [], - links : [], - constraints : [ - { type:"alignment", axis:"x", offsets:[] }, - { type:"alignment", axis:"y", offsets:[] } - ] - }; - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - - if(node.type == 'input'){ - if(this.input == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.input-1) * input++}); - } - json.constraints[1].offsets.push({node:i, offset : 0}); - } else if (node.type == 'output'){ - if(this.output == 1){ - json.constraints[0].offsets.push({node:i, offset: 0}); - } else { - json.constraints[0].offsets.push({node:i, offset : 0.8 * width / (this.output-1) * output++}); - } - json.constraints[1].offsets.push({node:i, offset : -0.8 * height}); - } - - json.nodes.push({ - id: i, - name: node.type == 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation : node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for(var i = 0; i < connections.length; i++){ - var connection = connections[i]; - if(connection.gater == null){ - json.links.push({ - source : this.nodes.indexOf(connection.from), - target : this.nodes.indexOf(connection.to), - weight : connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1/2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1/2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function(){ - var json = { - nodes : [], - connections : [], - input : this.input, - output : this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].index = i; - } - - for(var i = 0; i < this.nodes.length; i++){ - var node = this.nodes[i]; - var tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if(node.connections.self.weight != 0){ - var tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for(var i = 0; i < this.connections.length; i++){ - var conn = this.connections[i]; - var tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function(values){ - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function(set, options){ - options = options || {}; - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitnessFunction(genome){ - var score = 0; - for(var i = 0; i < amount; i++){ - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score/amount; - } - - options.network = this; - var neat = new Neat(0,0, fitnessFunction, options); - - var fitness = -Infinity; - var bestFitness = -Infinity; - var bestGenome = null; - - while(fitness < -targetError && (iterations == 0 || neat.generation < iterations)){ - neat.evolve(); - var fittest = neat.getFittest(); - var fitness = fittest.score; - var error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if(fitness > bestFitness){ - bestFitness = fitness; - bestGenome = fittest; - } - - if(log && neat.generation % log == 0){ - console.log('generation', neat.generation, 'fitness', fitness, 'error', -error); - } - - if(schedule && neat.generation % schedule.iterations == 0){ - schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(clear) bestGenome.clear(); - - var results = { - error: bestFitness, - generations: neat.generation, - time: Date.now() - start - }; - - if(bestGenome != null){ - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - } - - return results; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function(){ - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - for(var i = 0; i < this.input; i++){ - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];') - - // So we don't have to use expensive .indexOf() - for(var i = 0; i < this.nodes.length; i++){ - this.nodes[i].index = i; - } - - for(var i = this.input; i < this.nodes.length; i++){ - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if(present.indexOf(node.squash.name) == -1){ - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for(var j = 0; j < node.connections.in.length; j++){ - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if(conn.gater != null){ - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if(node.connections.self.weight){ - var conn = node.connections.self; - var computation = `S[${i}] * ${conn.weight}`; - - if(conn.gater != null){ - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for(var i = this.nodes.length - this.output; i < this.nodes.length; i++){ - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join("\r\n")}\r\n}`; - - return total; - } -}; - -/** - * Convert a json object to a network - */ - Network.fromJSON = function(json){ - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - for(var i = 0; i < json.nodes.length; i++){ - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for(var i = 0; i < json.connections.length; i++){ - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if(conn.gater != null){ - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; - } - - /** - * Merge two networks into one - */ - Network.merge = function(network1, network2){ - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if(network1.output != network2.input){ - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input to network1 output - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - if(conn.from.type == 'input'){ - var index = network2.nodes.indexOf(conn.from); - var node = network2.nodes[index]; - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for(var i = network2.input - 1; i >= 0; i--){ - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for(var i = network1.nodes.length - network1.output; i < network1.nodes.length; i++){ - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; - } - -/** - * Create an offspring from two parent networks - */ - Network.crossOver = function(network1, network2, equal){ - if(network1.input != network2.input || network1.output != network2.output){ - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - if(equal || score1 == score2){ - var max = Math.max(network1.nodes.length, network2.nodes.length); - var min = Math.min(network1.nodes.length, network2.nodes.length); - var size = Math.floor(Math.random() * (max - min + 1) + min); - } else if(score1 > score2){ - var size = network1.nodes.length; - } else { - var size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - for(var i = 0; i < size; i++){ - // Determine if an output node is needed - if(i < size - outputSize){ - var random = Math.random(); - var node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - var other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if(typeof node == 'undefined' || node.type == 'output'){ - node = other; - } - } else { - if(Math.random() >= 0.5){ - var node = network1.nodes[network1.nodes.length + i - size]; - } else { - var node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for(var i = 0; i < network1.connections.length; i++){ - var conn = network1.connections[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network1.selfconns.length; i++){ - var conn = network1.selfconns[i]; - var data = { - weight: conn.weight, - from : network1.nodes.indexOf(conn.from), - to : network1.nodes.indexOf(conn.to), - gater : network1.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n1conns.push(data); - } - - // Normal connections - for(var i = 0; i < network2.connections.length; i++){ - var conn = network2.connections[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Selfconnections - for(var i = 0; i < network2.selfconns.length; i++){ - var conn = network2.selfconns[i]; - var data = { - weight: conn.weight, - from : network2.nodes.indexOf(conn.from), - to : network2.nodes.indexOf(conn.to), - gater : network2.nodes.indexOf(conn.gater) - }; - var id = Connection.innovationID(data.from, data.to); - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for(var i = n1conns.length - 1; i >= 0; i--){ - var found = false; - for(var j = n2conns.length - 1; j >= 0; j--){ - // Common gene - if(n1conns[i].from == n2conns[j].from && n1conns[i].to == n2conns[j].to){ - var conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - var found = true; - break; - } - } - // Excess/disjoint gene - if(!found && (score1 >= score2 || equal)){ - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if(score2 >= score1 || equal){ - for(var i = 0; i < n2conns.length; i++){ - if(n2conns[i][0] != -1 && n2conns[i][1] != -1){ - connections.push(n2conns[i]); - } - } - } - - - // Add common conn genes uniformly - for(var i = 0; i < connections.length; i++){ - var connData = connections[i]; - if(connData.to < size && connData.from < size){ - var from = offspring.nodes[connData.from]; - var to = offspring.nodes[connData.to]; - var conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if(connData.gater != -1 && connData.gater < size){ - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; - } - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); -var Node = __webpack_require__(2); -var Group = __webpack_require__(5); -var Layer = __webpack_require__(6); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function(list){ - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - for(var i = 0; i < list.length; i++){ - if(list[i] instanceof Group){ - for(var j = 0; j < list[i].nodes.length; j++){ - nodes.push(list[i].nodes[j]); - } - } else if(list[i] instanceof Layer){ - for(var j = 0; j < list[i].nodes.length; j++){ - for(var k = 0; k < list[i].nodes[j].nodes.length; k++){ - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if(list[i] instanceof Node){ - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for(var i = nodes.length - 1; i >= 0; i--){ - if(nodes[i].type == 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length == 0){ - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if(nodes[i].type == 'input' || !nodes[i].connections.in.length){ - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if(network.input == 0 || network.output == 0){ - throw new Error('Given nodes have no clear input/output node!'); - } - - for(var i = 0; i < nodes.length; i++){ - for(var j = 0; j < nodes[i].connections.out.length; j++){ - network.connections.push(nodes[i].connections.out[j]); - } - for(var j = 0; j < nodes[i].connections.gated.length; j++){ - network.gates.push(nodes[i].connections.gated[j]); - } - if(nodes[i].connections.self.weight != 0){ - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function() { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for(var i = 1; i < layers.length; i++){ - var layer = layers[i]; - var layer = new Group(layer); - nodes.push(layer); - nodes[i-1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - - /** - * Creates a randomly connected network - */ - Random: function(input, hidden, output, options){ - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - for(var i = 0; i < hidden; i++){ - network.mutate(Methods.Mutation.ADD_NODE); - } - - for(var i = 0; i < connections - hidden; i++){ - network.mutate(Methods.Mutation.ADD_CONN); - } - - for(var i = 0; i < backconnections; i++){ - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for(var i = 0; i < selfconnections; i++){ - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for(var i = 0; i < gates; i++){ - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var last = args.pop(); - - if(typeof last == 'number'){ - var outputLayer = new Group(last); - last = {}; - } else { - var outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ type: 'output'}); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput == undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep == undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ type: 'input'}); - - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i == blocks.length-1 ? outputLayer : new Group(block); - - inputGate.set({ bias:1 }); - forgetGate.set({ bias:1 }); - outputGate.set({ bias:1 }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if(options.inputToDeep && i > 0){ - var input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if(options.memoryToMemory){ - var input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToMemory){ - var input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if(options.outputToGates){ - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if(i != blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if(options.inputToOutput){ - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function(){ - var args = Array.prototype.slice.call(arguments); - if (args.length < 3){ - throw new Error("not enough layers (minimum 3) !!"); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for(var i = 0; i < blocks.length; i++){ - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function(size){ - var input = new Group(size); - var output = new Group(size) - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({type: 'input'}); - output.set({squash: Methods.Activation.STEP, type: 'output'}); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function(inputSize, hiddenLayers, outputSize, previousInput, previousOutput){ - if(!Array.isArray(hiddenLayers)){ - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for(var i = 0; i < hiddenLayers.length; i++){ - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer) - if(typeof hidden[i-1] != 'undefined'){ - hidden[i-1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length-1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ type: 'input' }); - output.set({ type: 'output' }); - - return Architect.Construct(nodes); - } -} - -/* Export */ -if (module) module.exports = Architect; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Export */ -if (module) module.exports = Neat; - -/* Import */ -var Node = __webpack_require__(2); -var Network = __webpack_require__(7); -var Methods = __webpack_require__(1); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; -var Selection = Methods.Selection; -var Crossover = Methods.Crossover; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat(input, output, fitness, options){ - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE]; - this.mutation = options.mutation || Methods.Mutation.FFW; - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function(network){ - this.population = []; - - for(var i = 0; i < this.popsize; i++){ - if(this.template){ - var copy = Network.fromJSON(network.toJSON()); - } else { - var copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function(){ - // Check if evaluated, sort the population - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - var elitists = []; - for(var i = 0; i < this.elitism; i++){ - elitists.push(this.population[i]); - } - - // Provenance - for(var i = 0; i < this.provenance; i++){ - newPopulation.push(Network.fromJSON(this.template.toJSON())) - } - - // Breed the next individuals - for(var i = 0; i < this.popsize - this.elitism - this.provenance; i++){ - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - for(var i = 0; i < elitists.length; i++){ - this.population.push(elitists[i]); - } - - // Reset the scores - for(var i = 0; i < this.population.length; i++){ - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function(){ - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function(){ - // Elitist genomes should not be included - for(var i = 0; i < this.population.length; i++){ - if(Math.random() <= this.mutationRate){ - for(var j = 0; j < this.mutationAmount; j++){ - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function(){ - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - if(this.clear) genome.clear(); - var score = this.fitness(genome); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function(){ - this.population.sort(function(a,b){ - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function(){ - // Check if evaluated - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function(){ - if(this.population[this.population.length-1].score == null){ - this.evaluate(); - } - - var score = 0; - for(var i = 0; i < this.population.length; i++){ - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function(){ - switch(this.selection){ - case Selection.POWER: - if(this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - break; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for(var i = 0; i < this.population.length; i++){ - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - value += genome.score + minimalFitness; - if(random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - break; - case Selection.TOURNAMENT: - if(this.selection.size > this.popsize){ - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for(var i = 0; i < this.selection.size; i++){ - var random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function(a,b){ - return b.score - a.score; - }); - - // Select an individual - for(var i = 0; i < this.selection.size; i++){ - if(Math.random() < this.selection.probability || i == this.selection.size - 1){ - return individuals[i]; - - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function(){ - var json = []; - for(var i = 0; i < this.population.length; i++){ - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function(json){ - var population = []; - for(var i = 0; i < json.length; i++){ - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC : function(x, derivate){ - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) - return fx; - return fx * (1 - fx); - }, - TANH : function(x, derivate){ - if(derivate) - return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY : function(x, derivate){ - return derivate ? 1 : x; - }, - STEP : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU : function(x, derivate){ - if (derivate) - return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN : function(x, derivate){ - var d = 1 + Math.abs(x); - if(derivate) - return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID : function(x, derivate){ - if(derivate) - return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN : function(x, derivate){ - var d = Math.exp(-Math.pow(x, 2)); - if(derivate) - return -2 * x * d; - return d; - }, - BENT_IDENTITY: function(x, derivate){ - var d = Math.sqrt(Math.pow(x, 2) + 1); - if(derivate) - return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR : function(x, derivate){ - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID : function(x, derivate){ - var d = 2 / (1 + Math.exp(-x)) - 1; - if(derivate) - return 1/2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH : function(x, derivate){ - if(derivate) - return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE : function(x, derivate){ - if(derivate) - return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE : function(x, derivate){ - if(derivate) - return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function(x, derivate){ - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if(derivate) - return x > 0 ? scale : (fx + alpha) * scale; - return fx * scale; - } -}; - -/* Export */ -if (module) module.exports = Activation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL : { - name : "OUTPUT" - }, - ALL_TO_ELSE : { - name : "INPUT" - }, - ONE_TO_ONE : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Connection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i],1e-15)) + (1-target[i]) * Math.log(1 - Math.max(output[i],1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function(target, output){ - var misses = 0; - for(var i = 0; i < output.length; i++){ - misses += Math.round(target[i] * 2) != Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function(target, output){ - var error = 0; - for(var i = 0; i < output.length; i++){ - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -if (module) module.exports = Cost; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 13 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: "SINGLE_POINT", - config: [0.4] - }, - TWO_POINT: { - name: "TWO_POINT", - config: [0.4, 0.9] - }, - UNIFORM: { - name: "UNIFORM" - }, - AVERAGE: { - name: "AVERAGE" - } -}; - -/* Export */ -if (module) module.exports = Crossover; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT : { // not yet implemented - name : "OUTPUT" - }, - INPUT : { // not yet implemented - name : "INPUT" - }, - SELF : { - name: "SELF" - } -}; - -/* Export */ -if (module) module.exports = Gating; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 15 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/* Import */ -var Activation = __webpack_require__(10); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -//https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE : { - name : "ADD_NODE" - }, - SUB_NODE : { - name : "SUB_NODE", - keep_gates: true - }, - ADD_CONN : { - name : "ADD_CONN" - }, - SUB_CONN : { - name : "REMOVE_CONN" - }, - MOD_WEIGHT : { - name: "MOD_WEIGHT", - min: -1, - max: 1 - }, - MOD_BIAS : { - name: "MOD_BIAS", - min: -1, - max: 1 - }, - MOD_ACTIVATION : { - name : "MOD_ACTIVATION", - mutateOutput: true, - allowed : [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN : { - name: "ADD_SELF_CONN" - }, - SUB_SELF_CONN : { - name: "SUB_SELF_CONN" - }, - ADD_GATE : { - name: "ADD_GATE" - }, - SUB_GATE : { - name: "SUB_GATE" - }, - ADD_BACK_CONN : { - name: "ADD_BACK_CONN" - }, - SUB_BACK_CONN : { - name: "SUB_BACK_CONN" - }, - SWAP_NODES : { - name: "SWAP_NODES", - mutateOutput: true - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN, - Mutation.SWAP_NODES -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.SWAP_NODES -]; - -/* Export */ -if (module) module.exports = Mutation; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED : function(){ - var func = function(baseRate, iteration){ return baseRate }; - return func; - }, - STEP : function(gamma, stepSize){ - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP : function(gamma){ - gamma = gamma || 0.999; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(gamma, iteration); - } - - return func; - }, - INV : function(gamma, power){ - gamma = gamma || 0.001; - power = power || 2; - - var func = function(baseRate, iteration){ - return baseRate * Math.pow(1 + gamma * iteration, -power); - } - - return func; - } -}; - -/* Export */ -if (module) module.exports = Rate; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(module) {/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: "FITNESS_PROPORTIONATE" - }, - POWER: { - name: "POWER", - power: 4 - }, - TOURNAMENT: { - name: "TOURNAMENT", - size: 5, - probability: 0.5 - } -}; - -/* Export */ -if (module) module.exports = Selection; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0)(module))) - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Node : __webpack_require__(2), - Neat : __webpack_require__(9), - Network : __webpack_require__(7), - Methods : __webpack_require__(1), - Architect : __webpack_require__(8), - Group : __webpack_require__(5), - Connection : __webpack_require__(4), - Config : __webpack_require__(3), - Layer : __webpack_require__(6) -}; - -// CommonJS & AMD -if (true) -{ - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function(){ return Neataptic }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) -{ - module.exports = Neataptic; -} - -// Browser -if (typeof window == 'object') -{ - (function(){ - var old = window['neataptic']; - Neataptic.ninja = function(){ - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.34/neataptic.js b/node_modules/neataptic/docs/cdn/1.2.34/neataptic.js deleted file mode 100644 index 6791b9d..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.34/neataptic.js +++ /dev/null @@ -1,3625 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 17); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation: __webpack_require__(8), - Mutation: __webpack_require__(14), - Selection: __webpack_require__(16), - Crossover: __webpack_require__(12), - Cost: __webpack_require__(11), - Gating: __webpack_require__(13), - Connection: __webpack_require__(10), - Rate: __webpack_require__(15) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Methods; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Methods; -} - -// Browser -if (typeof window === 'object') { - (function () { - var oldMethods = window['methods']; - Methods.ninja = function () { - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var Methods = __webpack_require__(0); -var Connection = __webpack_require__(6); -var Config = __webpack_require__(2); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in Methods.Mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in Activation) { - if (Activation[squash].name === json.squash) { - node.squash = Activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: false -}; - -/* Export */ -module.exports = Config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(0); -var Config = __webpack_require__(2); -var Layer = __webpack_require__(4); -var Node = __webpack_require__(1); - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if (Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if (method === Methods.Connection.ALL_TO_ALL || method === Methods.Connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === Methods.Connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === Methods.Connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case Methods.Gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(0); -var Group = __webpack_require__(3); -var Node = __webpack_require__(1); - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: Methods.Activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: Methods.Activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: Methods.Activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], Methods.Connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var Methods = __webpack_require__(0); -var Config = __webpack_require__(2); -var Neat = __webpack_require__(7); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - var i; - for (i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (Methods.Mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (Methods.Mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (Config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (Config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - - if (typeof options.iterations === 'undefined') { - if (Config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if (batchSize > set.length) throw new Error('Batch size must be smaller or equal to dataset length!'); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - if (Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if (crossValidate) { - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (iterations === 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (clear) this.clear(); - error += this.test(testSet, cost).error; - if (clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if (clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (log && iteration % log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (schedule && iteration % schedule.iterations === 0) { - schedule.function({ - error: error, - iteration: iteration - }); - } - } - - if (clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function (set, options) { - options = options || {}; - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitnessFunction (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score / amount; - } - - options.network = this; - var neat = new Neat(0, 0, fitnessFunction, options); - - var fitness = -Infinity; - var bestFitness = -Infinity; - var bestGenome = null; - - while (fitness < -targetError && (iterations === 0 || neat.generation < iterations)) { - neat.evolve(); - let fittest = neat.getFittest(); - fitness = fittest.score; - let error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (log && neat.generation % log === 0) { - console.log('generation', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (schedule && neat.generation % schedule.iterations === 0) { - schedule.function({ - fitness: fitness, - error: -error, - iteration: neat.generation - }); - } - } - - if (clear) bestGenome.clear(); - - var results = { - error: bestFitness, - generations: neat.generation, - time: Date.now() - start - }; - - if (bestGenome != null) { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - } - - return results; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - var i; - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: network1.nodes.indexOf(conn.from), - to: network1.nodes.indexOf(conn.to), - gater: network1.nodes.indexOf(conn.gater) - }; - n1conns.push(data); - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: network1.nodes.indexOf(conn.from), - to: network1.nodes.indexOf(conn.to), - gater: network1.nodes.indexOf(conn.gater) - }; - n1conns.push(data); - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: network2.nodes.indexOf(conn.from), - to: network2.nodes.indexOf(conn.to), - gater: network2.nodes.indexOf(conn.gater) - }; - n2conns.push(data); - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: network2.nodes.indexOf(conn.from), - to: network2.nodes.indexOf(conn.to), - gater: network2.nodes.indexOf(conn.gater) - }; - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for (i = n1conns.length - 1; i >= 0; i--) { - var found = false; - for (var j = n2conns.length - 1; j >= 0; j--) { - // Common gene - if (n1conns[i].from === n2conns[j].from && n1conns[i].to === n2conns[j].to) { - let conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - found = true; - break; - } - } - // Excess/disjoint gene - if (!found && (score1 >= score2 || equal)) { - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < n2conns.length; i++) { - if (n2conns[i][0] !== -1 && n2conns[i][1] !== -1) { - connections.push(n2conns[i]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Methods = __webpack_require__(0); -var Network = __webpack_require__(5); - -/* Easier variable naming */ -var Selection = Methods.Selection; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE - ]; - this.mutation = options.mutation || Methods.Mutation.FFW; - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - var elitists = []; - var i; - for (i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - for (i = 0; i < elitists.length; i++) { - this.population.push(elitists[i]); - } - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function () { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - var score = this.fitness(genome); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case Selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case Selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = Activation; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var Methods = __webpack_require__(0); -var Network = __webpack_require__(5); -var Group = __webpack_require__(3); -var Layer = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(Methods.Mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(Methods.Mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: Methods.Activation.STEP, - type: 'output' - }); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return Architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = Architect; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = Connection; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = Cost; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = Crossover; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = Gating; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var Activation = __webpack_require__(8); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN, - Mutation.SWAP_NODES -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.SWAP_NODES -]; - -/* Export */ -module.exports = Mutation; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = Rate; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = Selection; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Methods: __webpack_require__(0), - Connection: __webpack_require__(6), - Architect: __webpack_require__(9), - Network: __webpack_require__(5), - Config: __webpack_require__(2), - Group: __webpack_require__(3), - Layer: __webpack_require__(4), - Node: __webpack_require__(1), - Neat: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.2.34/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.2.34/neataptic.min.js deleted file mode 100644 index 6791b9d..0000000 --- a/node_modules/neataptic/docs/cdn/1.2.34/neataptic.min.js +++ /dev/null @@ -1,3625 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 17); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Methods = { - Activation: __webpack_require__(8), - Mutation: __webpack_require__(14), - Selection: __webpack_require__(16), - Crossover: __webpack_require__(12), - Cost: __webpack_require__(11), - Gating: __webpack_require__(13), - Connection: __webpack_require__(10), - Rate: __webpack_require__(15) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Methods; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Methods; -} - -// Browser -if (typeof window === 'object') { - (function () { - var oldMethods = window['methods']; - Methods.ninja = function () { - window['methods'] = oldMethods; - return Methods; - }; - })(); - - window['methods'] = Methods; -} - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var Methods = __webpack_require__(0); -var Connection = __webpack_require__(6); -var Config = __webpack_require__(2); - -/* Easier variable naming */ -var Activation = Methods.Activation; -var Mutation = Methods.Mutation; - -/****************************************************************************************** - NODE -*******************************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = Activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // note: MINI_BATCH SHALL BE OPTIMIZED SOON - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (Config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in Methods.Mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case Mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case Mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in Activation) { - if (Activation[squash].name === json.squash) { - node.squash = Activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - CONFIG -*******************************************************************************************/ - -// Config -var Config = { - warnings: false -}; - -/* Export */ -module.exports = Config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var Methods = __webpack_require__(0); -var Config = __webpack_require__(2); -var Layer = __webpack_require__(4); -var Node = __webpack_require__(1); - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (Config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = Methods.Connection.ALL_TO_ALL; - } else { - if (Config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = Methods.Connection.ONE_TO_ONE; - } - } - if (method === Methods.Connection.ALL_TO_ALL || method === Methods.Connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === Methods.Connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === Methods.Connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case Methods.Gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case Methods.Gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case Methods.Gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var Methods = __webpack_require__(0); -var Group = __webpack_require__(3); -var Node = __webpack_require__(1); - -/****************************************************************************************** - Group -*******************************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, Methods.Gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: Methods.Activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: Methods.Activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: Methods.Activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, Methods.Connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, Methods.Connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, Methods.Connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - - resetGate.gate(reset, Methods.Gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, Methods.Connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, Methods.Connection.ALL_TO_ALL); - - updateGate.gate(update1, Methods.Gating.OUTPUT); - inverseUpdateGate.gate(update2, Methods.Gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, Methods.Connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: Methods.Activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, Methods.Connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || Methods.Connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], Methods.Connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var Methods = __webpack_require__(0); -var Config = __webpack_require__(2); -var Neat = __webpack_require__(7); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var Mutation = Methods.Mutation; - -/******************************************************************************************* - NETWORK -*******************************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (Config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - var i; - for (i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (Methods.Mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (Methods.Mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case Mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(Mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case Mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (Config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case Mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case Mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case Mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (Config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case Mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (Config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case Mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (Config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case Mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (Config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case Mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (Config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case Mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (Config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case Mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (Config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case Mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (Config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (Config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - - if (typeof options.iterations === 'undefined') { - if (Config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - var start = Date.now(); - - // Configure given options - var log = options.log || false; - var targetError = options.error || 0.05; - var cost = options.cost || Methods.Cost.MSE; - var baseRate = options.rate || 0.3; - var shuffle = options.shuffle || false; - var iterations = options.iterations || 0; - var crossValidate = options.crossValidate || false; - var clear = options.clear || false; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || Methods.Rate.FIXED(); - var schedule = options.schedule; - - if (batchSize > set.length) throw new Error('Batch size must be smaller or equal to dataset length!'); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - if (Config.warnings) console.warn('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } - - // Save to network - this.dropout = dropout; - - if (crossValidate) { - var testSize = options.crossValidate.testSize; - var testError = options.crossValidate.testError; - var numTrain = Math.ceil((1 - testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (iterations === 0 || iteration < iterations)) { - if (crossValidate && error <= testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - error = 0; - - // Checks if cross validation is enabled - if (crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (clear) this.clear(); - error += this.test(testSet, cost).error; - if (clear) this.clear(); - } else { - error += this._trainSet(set, batchSize, currentRate, momentum, cost); - if (clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (log && iteration % log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (schedule && iteration % schedule.iterations === 0) { - schedule.function({ - error: error, - iteration: iteration - }); - } - } - - if (clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - // Creates an object of the results - var results = { - error: error, - iterations: iteration, - time: Date.now() - start - }; - - return results; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || Methods.Cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: function (set, options) { - options = options || {}; - var cost = options.cost || Methods.Cost.MSE; - var amount = options.amount || 1; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var iterations = options.iterations || 0; - var targetError = options.error || 0.005; - var log = options.log || 0; - var clear = options.clear || false; - var schedule = options.schedule; - - var start = Date.now(); - - function fitnessFunction (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - return score / amount; - } - - options.network = this; - var neat = new Neat(0, 0, fitnessFunction, options); - - var fitness = -Infinity; - var bestFitness = -Infinity; - var bestGenome = null; - - while (fitness < -targetError && (iterations === 0 || neat.generation < iterations)) { - neat.evolve(); - let fittest = neat.getFittest(); - fitness = fittest.score; - let error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (log && neat.generation % log === 0) { - console.log('generation', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (schedule && neat.generation % schedule.iterations === 0) { - schedule.function({ - fitness: fitness, - error: -error, - iteration: neat.generation - }); - } - } - - if (clear) bestGenome.clear(); - - var results = { - error: bestFitness, - generations: neat.generation, - time: Date.now() - start - }; - - if (bestGenome != null) { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.gates = bestGenome.gates; - this.selfconns = bestGenome.selfconns; - } - - return results; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Assign nodes from parents to offspring - var i; - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = []; - var n2conns = []; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: network1.nodes.indexOf(conn.from), - to: network1.nodes.indexOf(conn.to), - gater: network1.nodes.indexOf(conn.gater) - }; - n1conns.push(data); - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: network1.nodes.indexOf(conn.from), - to: network1.nodes.indexOf(conn.to), - gater: network1.nodes.indexOf(conn.gater) - }; - n1conns.push(data); - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: network2.nodes.indexOf(conn.from), - to: network2.nodes.indexOf(conn.to), - gater: network2.nodes.indexOf(conn.gater) - }; - n2conns.push(data); - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: network2.nodes.indexOf(conn.from), - to: network2.nodes.indexOf(conn.to), - gater: network2.nodes.indexOf(conn.gater) - }; - n2conns.push(data); - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - for (i = n1conns.length - 1; i >= 0; i--) { - var found = false; - for (var j = n2conns.length - 1; j >= 0; j--) { - // Common gene - if (n1conns[i].from === n2conns[j].from && n1conns[i].to === n2conns[j].to) { - let conn = Math.random() >= 0.5 ? n1conns[i] : n2conns[j]; - connections.push(conn); - - // Because splicing is expensive, we set to -1 -1 - n2conns[j] = [-1, -1]; - found = true; - break; - } - } - // Excess/disjoint gene - if (!found && (score1 >= score2 || equal)) { - connections.push(n1conns[i]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < n2conns.length; i++) { - if (n2conns[i][0] !== -1 && n2conns[i][1] !== -1) { - connections.push(n2conns[i]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/****************************************************************************************** - CONNECTION -*******************************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Methods = __webpack_require__(0); -var Network = __webpack_require__(5); - -/* Easier variable naming */ -var Selection = Methods.Selection; - -/******************************************************************************************* - NEAT -*******************************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.selection = options.selection || Methods.Selection.POWER; - this.crossover = options.crossover || [Methods.Crossover.SINGLE_POINT, - Methods.Crossover.TWO_POINT, - Methods.Crossover.UNIFORM, - Methods.Crossover.AVERAGE - ]; - this.mutation = options.mutation || Methods.Mutation.FFW; - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - this.sort(); - - var newPopulation = []; - - // Elitism - var elitists = []; - var i; - for (i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - for (i = 0; i < elitists.length; i++) { - this.population.push(elitists[i]); - } - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: function () { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - var score = this.fitness(genome); - this.population[i].score = score; - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case Selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case Selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case Selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change Methods.Selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var Activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = Activation; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var Methods = __webpack_require__(0); -var Network = __webpack_require__(5); -var Group = __webpack_require__(3); -var Layer = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************************* - ARCHITECT -*******************************************************************************************/ - -var Architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], Methods.Connection.ALL_TO_ALL); - } - - // Construct the network - return Architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(Methods.Mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(Methods.Mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(Methods.Mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(Methods.Mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(Methods.Mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - previous.connect(inputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(outputGate, Methods.Connection.ALL_TO_ALL); - previous.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - memoryCell.connect(outputGate, Methods.Connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, Methods.Connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, Methods.Connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, Methods.Gating.INPUT); - forgetGate.gate(forget, Methods.Gating.SELF); - outputGate.gate(output, Methods.Gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, Methods.Connection.ALL_TO_ELSE); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, Methods.Connection.ALL_TO_ALL); - inputGate.gate(input, Methods.Gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, Methods.Connection.ALL_TO_ALL); - outputLayer.connect(outputGate, Methods.Connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, Methods.Connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return Architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return Architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, Methods.Connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: Methods.Activation.STEP, - type: 'output' - }); - - var network = new Architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, Methods.Connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - input.connect(inputMemory, Methods.Connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, Methods.Connection.ALL_TO_ALL); - output.connect(outputMemory, Methods.Connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], Methods.Connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return Architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = Architect; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - CONNECTION -*******************************************************************************************/ - -// Specifies in what manner two groups are connected -var Connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = Connection; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - COST FUNCTIONS -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var Cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = Cost; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - CROSSOVER -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var Crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = Crossover; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - GATING -*******************************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var Gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = Gating; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var Activation = __webpack_require__(8); - -/******************************************************************************************* - MUTATION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Mutation_(genetic_algorithm) -var Mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - Activation.LOGISTIC, - Activation.TANH, - Activation.RELU, - Activation.IDENTITY, - Activation.STEP, - Activation.SOFTSIGN, - Activation.SINUSOID, - Activation.GAUSSIAN, - Activation.BENT_IDENTITY, - Activation.BIPOLAR, - Activation.BIPOLAR_SIGMOID, - Activation.HARD_TANH, - Activation.ABSOLUTE, - Activation.INVERSE, - Activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -Mutation.ALL = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.ADD_GATE, - Mutation.SUB_GATE, - Mutation.ADD_SELF_CONN, - Mutation.SUB_SELF_CONN, - Mutation.ADD_BACK_CONN, - Mutation.SUB_BACK_CONN, - Mutation.SWAP_NODES -]; - -Mutation.FFW = [ - Mutation.ADD_NODE, - Mutation.SUB_NODE, - Mutation.ADD_CONN, - Mutation.SUB_CONN, - Mutation.MOD_WEIGHT, - Mutation.MOD_BIAS, - Mutation.MOD_ACTIVATION, - Mutation.SWAP_NODES -]; - -/* Export */ -module.exports = Mutation; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - RATE -*******************************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var Rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = Rate; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************************* - SELECTION -*******************************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var Selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = Selection; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - Methods: __webpack_require__(0), - Connection: __webpack_require__(6), - Architect: __webpack_require__(9), - Network: __webpack_require__(5), - Config: __webpack_require__(2), - Group: __webpack_require__(3), - Layer: __webpack_require__(4), - Node: __webpack_require__(1), - Neat: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.0/neataptic.js b/node_modules/neataptic/docs/cdn/1.3.0/neataptic.js deleted file mode 100644 index fe84aae..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.0/neataptic.js +++ /dev/null @@ -1,3917 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(threads > 1){ - for(var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.states); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.Mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - S[index] = data[i++]; // bias - let squash = data[i++]; - while (data[i] !== -2) { - if (index === A[data[i]]) { // selfconn - S[index] += S[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } else { // normal conn - S[index] += A[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.Gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.Gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.Gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - var onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.0/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.3.0/neataptic.min.js deleted file mode 100644 index fe84aae..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.0/neataptic.min.js +++ /dev/null @@ -1,3917 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(threads > 1){ - for(var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.states); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.Mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - S[index] = data[i++]; // bias - let squash = data[i++]; - while (data[i] !== -2) { - if (index === A[data[i]]) { // selfconn - S[index] += S[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } else { // normal conn - S[index] += A[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.Gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.Gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.Gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - var onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.1/neataptic.js b/node_modules/neataptic/docs/cdn/1.3.1/neataptic.js deleted file mode 100644 index eeb9b50..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.1/neataptic.js +++ /dev/null @@ -1,3917 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(threads > 1){ - for(var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.states); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - S[index] = data[i++]; // bias - let squash = data[i++]; - while (data[i] !== -2) { - if (index === A[data[i]]) { // selfconn - S[index] += S[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } else { // normal conn - S[index] += A[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.Gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.Gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.Gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - var onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.1/neataptic.min.js b/node_modules/neataptic/docs/cdn/1.3.1/neataptic.min.js deleted file mode 100644 index eeb9b50..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.1/neataptic.min.js +++ /dev/null @@ -1,3917 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(threads > 1){ - for(var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.states); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - S[index] = data[i++]; // bias - let squash = data[i++]; - while (data[i] !== -2) { - if (index === A[data[i]]) { // selfconn - S[index] += S[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } else { // normal conn - S[index] += A[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.Gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.Gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.Gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - var onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.2/neataptic.js b/node_modules/neataptic/docs/cdn/1.3.2/neataptic.js deleted file mode 100644 index 6f0c8f7..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.2/neataptic.js +++ /dev/null @@ -1,3924 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - if (threads > 1 && set[0].input.length + set[0].output.length < 100) { - console.warn( - `Multithreading is automatically enabled, but for small datasets, we - encourage using just 1 thread!` - ); - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(threads > 1){ - for(var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - S[index] = data[i++]; // bias - let squash = data[i++]; - while (data[i] !== -2) { - if (index === A[data[i]]) { // selfconn - S[index] += S[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } else { // normal conn - S[index] += A[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.Gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.Gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.Gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.3/neataptic.js b/node_modules/neataptic/docs/cdn/1.3.3/neataptic.js deleted file mode 100644 index 133ab44..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.3/neataptic.js +++ /dev/null @@ -1,3924 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - if (threads > 1 && set[0].input.length + set[0].output.length < 100) { - console.warn( - `Multithreading is automatically enabled, but for small datasets, we - encourage using just 1 thread!` - ); - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(threads > 1){ - for(var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - S[index] = data[i++]; // bias - let squash = data[i++]; - while (data[i] !== -2) { - if (index === A[data[i]]) { // selfconn - S[index] += S[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } else { // normal conn - S[index] += A[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.4/neataptic.js b/node_modules/neataptic/docs/cdn/1.3.4/neataptic.js deleted file mode 100644 index 4960a7f..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.4/neataptic.js +++ /dev/null @@ -1,3925 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - if (threads > 1 && set[0].input.length + set[0].output.length < 100) { - console.warn( - `Multithreading is automatically enabled, but for small datasets, we - encourage using just 1 thread!` - ); - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if(threads > 1){ - for(var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - S[index] = data[i++]; // bias - let squash = data[i++]; - while (data[i] !== -2) { - if (index === A[data[i]]) { // selfconn - S[index] += S[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } else { // normal conn - S[index] += A[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.5/neataptic.js b/node_modules/neataptic/docs/cdn/1.3.5/neataptic.js deleted file mode 100644 index 0e62ec2..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.5/neataptic.js +++ /dev/null @@ -1,3933 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - this.activation = 0; - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - if (threads > 1 && set[0].input.length + set[0].output.length < 100) { - console.warn( - `Multithreading is automatically enabled, but for small datasets, we - encourage using just 1 thread!` - ); - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - if (options.clear) genome.clear(); - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - if (options.clear) genome.clear(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - S[index] = data[i++]; // bias - let squash = data[i++]; - while (data[i] !== -2) { - if (index === A[data[i]]) { // selfconn - S[index] += S[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } else { // normal conn - S[index] += A[data[i++]] * data[i++] * - (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.6/neataptic.js b/node_modules/neataptic/docs/cdn/1.3.6/neataptic.js deleted file mode 100644 index ab0affc..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.6/neataptic.js +++ /dev/null @@ -1,3935 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - if (threads > 1 && set[0].input.length + set[0].output.length < 100) { - console.warn( - `Multithreading is automatically enabled, but for small datasets, we - encourage using just 1 thread!` - ); - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - if (options.clear) genome.clear(); - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - if (options.clear) genome.clear(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.7/neataptic.js b/node_modules/neataptic/docs/cdn/1.3.7/neataptic.js deleted file mode 100644 index e960a87..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.7/neataptic.js +++ /dev/null @@ -1,3935 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection - var node = this.nodes[Math.floor(Math.random() * this.nodes.length)]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - if (threads > 1 && set[0].input.length + set[0].output.length < 100) { - if (config.warnings) console.warn( - `Multithreading is automatically enabled, but for small datasets, we - encourage using just 1 thread!` - ); - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - if (options.clear) genome.clear(); - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - if (options.clear) genome.clear(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.8/neataptic.js b/node_modules/neataptic/docs/cdn/1.3.8/neataptic.js deleted file mode 100644 index 20c5cc9..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.8/neataptic.js +++ /dev/null @@ -1,3937 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - if (threads > 1 && set[0].input.length + set[0].output.length < 100) { - if (config.warnings) console.warn( - `Multithreading is automatically enabled, but for small datasets, we - encourage using just 1 thread!` - ); - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - if (options.clear) genome.clear(); - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - if (options.clear) genome.clear(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.3.9/neataptic.js b/node_modules/neataptic/docs/cdn/1.3.9/neataptic.js deleted file mode 100644 index 27f54cd..0000000 --- a/node_modules/neataptic/docs/cdn/1.3.9/neataptic.js +++ /dev/null @@ -1,3937 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(); - else if(typeof define === 'function' && define.amd) - define([], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(); - else - root["neataptic"] = factory(); -})(this, function() { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 21); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(16), - selection: __webpack_require__(18), - crossover: __webpack_require__(14), - cost: __webpack_require__(13), - gating: __webpack_require__(15), - connection: __webpack_require__(12), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - if (node === this && this.connections.self.weight !== 0) return true; - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - - for (var squash in methods.activation) { - if (methods.activation[squash].name === json.squash) { - node.squash = methods.activation[squash]; - break; - } - } - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = (i < this.input) ? 'input' : 'output'; - this.nodes.push(new Node(type, this.nodes.length)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target === 'undefined' || target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden', this.nodes.length); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - cost = cost || methods.cost.MSE; - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.activate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var threads = options.threads || (typeof navigator === 'undefined' ? 1 : navigator.hardwareConcurrency); - var amount = options.amount || 1; - - if (threads > 1 && set[0].input.length + set[0].output.length < 100) { - if (config.warnings) console.warn( - `Multithreading is automatically enabled, but for small datasets, we - encourage using just 1 thread!` - ); - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - if (options.clear) genome.clear(); - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - if (typeof window === 'undefined') { - throw new Error('Multithreading is not yet supported by Neataptic for Node.js'); - } - - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.TestWorker(converted, cost)); - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = neat.population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - if (options.clear) genome.clear(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - // Convert to Float64Arrays - activations = new Float64Array(activations); - states = new Float64Array(states); - conns = new Float64Array(conns); - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Snippets */ - snippets: __webpack_require__(10), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - } -}; - -/* Export */ -module.exports = multi; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = null; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (this.population[this.population.length - 1].score == null) { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = null; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - this.sort(); - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (this.population[this.population.length - 1].score == null) { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) { return fx; } - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) { return 1 - Math.pow(Math.tanh(x), 2); } - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) { return x > 0 ? 1 : 0; } - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) { return x / Math.pow(d, 2); } - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) { return Math.cos(x); } - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) { return -2 * x * d; } - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) { return x / (2 * d) + 1; } - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) { return 1 / 2 * (1 + d) * (1 - d); } - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) { return x > -1 && x < 1 ? 1 : 0; } - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) { return x < 0 ? -1 : 1; } - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) { return -1; } - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SNIPPETS -*******************************************************************************/ - -var snippets = { - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ], - - activate: function (input) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - testSerializedSet: function (set) { - var inOut = set[0] + set[1]; - - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < (set.length - 2) / inOut; i++) { - let input = []; - for (var j = 2 + i * inOut; j < 2 + i * inOut + set[0]; j++) { - input.push(set[j]); - } - let target = []; - for (j = 2 + i * inOut + set[0]; j < 2 + i * inOut + inOut; j++) { - target.push(set[j]); - } - - let output = activate(input); - error += cost(target, output); - } - - return error / ((set.length - 2) / inOut); - } -}; - -/** Export */ -module.exports = snippets; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { // not yet implemented - name: 'OUTPUT' - }, - INPUT: { // not yet implemented - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - TestWorker: __webpack_require__(20) -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var snippets = __webpack_require__(10); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialzed = network.serialize(); - - var data = { - activations: serialzed[0].buffer, - states: serialzed[1].buffer, - conns: serialzed[2].buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var A, S, data; - var F = [${snippets.activations.toString()}]; - var cost = ${cost.toString()}; - var test = ${snippets.testSerializedSet.toString()}; - var activate = ${snippets.activate.toString()}; - var set; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - A = new Float64Array(e.data.activations); - S = new Float64Array(e.data.states); - data = new Float64Array(e.data.conns); - - var error = test(set); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = new Float64Array(e.data.set); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(11), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.4.0/neataptic.js b/node_modules/neataptic/docs/cdn/1.4.0/neataptic.js deleted file mode 100644 index 00e7177..0000000 --- a/node_modules/neataptic/docs/cdn/1.4.0/neataptic.js +++ /dev/null @@ -1,4473 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("child_process"), require("os")); - else if(typeof define === 'function' && define.amd) - define(["child_process", "os"], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(require("child_process"), require("os")); - else - root["neataptic"] = factory(root["child_process"], root["os"]); -})(this, function(__WEBPACK_EXTERNAL_MODULE_23__, __WEBPACK_EXTERNAL_MODULE_24__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 25); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(17), - selection: __webpack_require__(19), - crossover: __webpack_require__(15), - cost: __webpack_require__(14), - gating: __webpack_require__(16), - connection: __webpack_require__(13), - rate: __webpack_require__(18) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Activates the node without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state); - - for (i = 0; i < this.connections.gated.length; i++) { - this.connections.gated[i].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) this.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - node.squash = methods.activation[json.squash]; - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = i < this.input ? 'input' : 'output'; - this.nodes.push(new Node(type)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - - return output; - }, - - /** - * Activates the network without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].noTraceActivate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].noTraceActivate(); - output.push(activation); - } else { - this.nodes[i].noTraceActivate(); - } - } - - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target !== 'undefined' && target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden'); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (this.selfconns.indexOf(node.connections.self) === -1) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost = methods.cost.MSE) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.noTraceActivate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var amount = options.amount || 1; - - var threads = options.threads; - if (typeof threads === 'undefined') { - if (typeof window === 'undefined') { // Node.js - threads = __webpack_require__(24).cpus().length; - } else { // Browser - threads = navigator.hardwareConcurrency; - } - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - if (typeof window === 'undefined') { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.node.TestWorker(converted, cost)); - } - } else { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.browser.TestWorker(converted, cost)); - } - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - for (i in bestGenome) this[i] = bestGenome[i]; - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (present.indexOf(node.squash.name) === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(22), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - }, - - /** Activate a serialized network */ - activateSerializedNetwork: function (input, A, S, data, F) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - /** Deserializes a dataset to an array of arrays */ - deserializeDataSet: function (serializedSet) { - var set = []; - - var sampleSize = serializedSet[0] + serializedSet[1]; - for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) { - let input = []; - for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) { - input.push(serializedSet[j]); - } - let output = []; - for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) { - output.push(serializedSet[j]); - } - set.push(input); - set.push(output); - } - - return set; - }, - - /** A list of compiled activation functions in a certain order */ - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ] -}; - -multi.testSerializedSet = function (set, cost, A, S, data, F) { - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < set.length; i += 2) { - let output = multi.activateSerializedNetwork(set[i], A, S, data, F); - error += cost(set[i + 1], output); - } - - return error / (set.length / 2); -}; - -/* Export */ -for (var i in multi) { - module.exports[i] = multi[i]; -} - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = undefined; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (typeof this.population[this.population.length - 1].score === 'undefined') { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = undefined; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - if (this.clear) { - for (var i = 0; i < this.population.length; i++) { - this.population[i].clear(); - } - } - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - if (this.population[0].score < this.population[1].score) { - this.sort(); - } - - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) return fx; - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) return -2 * x * d; - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) return 1 / 2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { - name: 'OUTPUT' - }, - INPUT: { - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var multi = __webpack_require__(7); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: new Float64Array(serialized[0]).buffer, - states: new Float64Array(serialized[1]).buffer, - conns: new Float64Array(serialized[2]).buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var F = [${multi.activations.toString()}]; - var cost = ${cost.toString()}; - var multi = { - deserializeDataSet: ${multi.deserializeDataSet.toString()}, - testSerializedSet: ${multi.testSerializedSet.toString()}, - activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} - }; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - var A = new Float64Array(e.data.activations); - var S = new Float64Array(e.data.states); - var data = new Float64Array(e.data.conns); - - var error = multi.testSerializedSet(set, cost, A, S, data, F); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = multi.deserializeDataSet(new Float64Array(e.data.set)); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var cp = __webpack_require__(23); -var path = __webpack_require__(11); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - this.worker = cp.fork(path.join(__dirname, '/worker')); - - this.worker.send({ set: dataSet, cost: cost.name }); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: serialized[0], - states: serialized[1], - conns: serialized[2] - }; - - var _that = this.worker; - this.worker.on('message', function callback (e) { - _that.removeListener('message', callback); - resolve(e); - }); - - this.worker.send(data); - }); - }, - - terminate: function () { - this.worker.kill(); - } -}; - - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - node: { - TestWorker: __webpack_require__(21) - }, - browser: { - TestWorker: __webpack_require__(20) - } -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_23__; - -/***/ }), -/* 24 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_24__; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(10), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.4.1/neataptic.js b/node_modules/neataptic/docs/cdn/1.4.1/neataptic.js deleted file mode 100644 index 45e1679..0000000 --- a/node_modules/neataptic/docs/cdn/1.4.1/neataptic.js +++ /dev/null @@ -1,4477 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("child_process"), require("os")); - else if(typeof define === 'function' && define.amd) - define(["child_process", "os"], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(require("child_process"), require("os")); - else - root["neataptic"] = factory(root["child_process"], root["os"]); -})(this, function(__WEBPACK_EXTERNAL_MODULE_23__, __WEBPACK_EXTERNAL_MODULE_24__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 25); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(17), - selection: __webpack_require__(19), - crossover: __webpack_require__(15), - cost: __webpack_require__(14), - gating: __webpack_require__(16), - connection: __webpack_require__(13), - rate: __webpack_require__(18) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Activates the node without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state); - - for (i = 0; i < this.connections.gated.length; i++) { - this.connections.gated[i].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) conn.gater.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - node.squash = methods.activation[json.squash]; - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = i < this.input ? 'input' : 'output'; - this.nodes.push(new Node(type)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - - return output; - }, - - /** - * Activates the network without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].noTraceActivate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].noTraceActivate(); - output.push(activation); - } else { - this.nodes[i].noTraceActivate(); - } - } - - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target === 'undefined' || target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden'); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (node.connections.self.weight === 0) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost = methods.cost.MSE) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.noTraceActivate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var amount = options.amount || 1; - - var threads = options.threads; - if (typeof threads === 'undefined') { - if (typeof window === 'undefined') { // Node.js - threads = __webpack_require__(24).cpus().length; - } else { // Browser - threads = navigator.hardwareConcurrency; - } - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - if (typeof window === 'undefined') { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.node.TestWorker(converted, cost)); - } - } else { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.browser.TestWorker(converted, cost)); - } - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.selfconns = bestGenome.selfconns; - this.gates = bestGenome.gates; - - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (functionIndex === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(22), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - }, - - /** Activate a serialized network */ - activateSerializedNetwork: function (input, A, S, data, F) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - /** Deserializes a dataset to an array of arrays */ - deserializeDataSet: function (serializedSet) { - var set = []; - - var sampleSize = serializedSet[0] + serializedSet[1]; - for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) { - let input = []; - for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) { - input.push(serializedSet[j]); - } - let output = []; - for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) { - output.push(serializedSet[j]); - } - set.push(input); - set.push(output); - } - - return set; - }, - - /** A list of compiled activation functions in a certain order */ - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ] -}; - -multi.testSerializedSet = function (set, cost, A, S, data, F) { - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < set.length; i += 2) { - let output = multi.activateSerializedNetwork(set[i], A, S, data, F); - error += cost(set[i + 1], output); - } - - return error / (set.length / 2); -}; - -/* Export */ -for (var i in multi) { - module.exports[i] = multi[i]; -} - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = undefined; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (typeof this.population[this.population.length - 1].score === 'undefined') { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = undefined; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - if (this.clear) { - for (var i = 0; i < this.population.length; i++) { - this.population[i].clear(); - } - } - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - if (this.population[0].score < this.population[1].score) { - this.sort(); - } - - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) return fx; - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) return -2 * x * d; - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) return 1 / 2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { - name: 'OUTPUT' - }, - INPUT: { - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var multi = __webpack_require__(7); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: new Float64Array(serialized[0]).buffer, - states: new Float64Array(serialized[1]).buffer, - conns: new Float64Array(serialized[2]).buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var F = [${multi.activations.toString()}]; - var cost = ${cost.toString()}; - var multi = { - deserializeDataSet: ${multi.deserializeDataSet.toString()}, - testSerializedSet: ${multi.testSerializedSet.toString()}, - activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} - }; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - var A = new Float64Array(e.data.activations); - var S = new Float64Array(e.data.states); - var data = new Float64Array(e.data.conns); - - var error = multi.testSerializedSet(set, cost, A, S, data, F); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = multi.deserializeDataSet(new Float64Array(e.data.set)); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var cp = __webpack_require__(23); -var path = __webpack_require__(11); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - this.worker = cp.fork(path.join(__dirname, '/worker')); - - this.worker.send({ set: dataSet, cost: cost.name }); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: serialized[0], - states: serialized[1], - conns: serialized[2] - }; - - var _that = this.worker; - this.worker.on('message', function callback (e) { - _that.removeListener('message', callback); - resolve(e); - }); - - this.worker.send(data); - }); - }, - - terminate: function () { - this.worker.kill(); - } -}; - - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - node: { - TestWorker: __webpack_require__(21) - }, - browser: { - TestWorker: __webpack_require__(20) - } -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_23__; - -/***/ }), -/* 24 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_24__; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(10), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.4.2/neataptic.js b/node_modules/neataptic/docs/cdn/1.4.2/neataptic.js deleted file mode 100644 index 50cdc04..0000000 --- a/node_modules/neataptic/docs/cdn/1.4.2/neataptic.js +++ /dev/null @@ -1,4479 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("child_process"), require("os")); - else if(typeof define === 'function' && define.amd) - define(["child_process", "os"], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(require("child_process"), require("os")); - else - root["neataptic"] = factory(root["child_process"], root["os"]); -})(this, function(__WEBPACK_EXTERNAL_MODULE_23__, __WEBPACK_EXTERNAL_MODULE_24__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 25); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(17), - selection: __webpack_require__(19), - crossover: __webpack_require__(15), - cost: __webpack_require__(14), - gating: __webpack_require__(16), - connection: __webpack_require__(13), - rate: __webpack_require__(18) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Activates the node without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state); - - for (i = 0; i < this.connections.gated.length; i++) { - this.connections.gated[i].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) conn.gater.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - node.squash = methods.activation[json.squash]; - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = i < this.input ? 'input' : 'output'; - this.nodes.push(new Node(type)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - - return output; - }, - - /** - * Activates the network without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].noTraceActivate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].noTraceActivate(); - output.push(activation); - } else { - this.nodes[i].noTraceActivate(); - } - } - - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target === 'undefined' || target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden'); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var allconnections = this.connections.concat(this.selfconns); - - var connection = allconnections[Math.floor(Math.random() * allconnections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (node.connections.self.weight === 0) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost = methods.cost.MSE) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.noTraceActivate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var amount = options.amount || 1; - - var threads = options.threads; - if (typeof threads === 'undefined') { - if (typeof window === 'undefined') { // Node.js - threads = __webpack_require__(24).cpus().length; - } else { // Browser - threads = navigator.hardwareConcurrency; - } - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - if (typeof window === 'undefined') { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.node.TestWorker(converted, cost)); - } - } else { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.browser.TestWorker(converted, cost)); - } - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.selfconns = bestGenome.selfconns; - this.gates = bestGenome.gates; - - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (functionIndex === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(22), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - }, - - /** Activate a serialized network */ - activateSerializedNetwork: function (input, A, S, data, F) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - /** Deserializes a dataset to an array of arrays */ - deserializeDataSet: function (serializedSet) { - var set = []; - - var sampleSize = serializedSet[0] + serializedSet[1]; - for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) { - let input = []; - for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) { - input.push(serializedSet[j]); - } - let output = []; - for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) { - output.push(serializedSet[j]); - } - set.push(input); - set.push(output); - } - - return set; - }, - - /** A list of compiled activation functions in a certain order */ - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ] -}; - -multi.testSerializedSet = function (set, cost, A, S, data, F) { - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < set.length; i += 2) { - let output = multi.activateSerializedNetwork(set[i], A, S, data, F); - error += cost(set[i + 1], output); - } - - return error / (set.length / 2); -}; - -/* Export */ -for (var i in multi) { - module.exports[i] = multi[i]; -} - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = undefined; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (typeof this.population[this.population.length - 1].score === 'undefined') { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = undefined; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - if (this.clear) { - for (var i = 0; i < this.population.length; i++) { - this.population[i].clear(); - } - } - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - if (this.population[0].score < this.population[1].score) { - this.sort(); - } - - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) return fx; - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) return -2 * x * d; - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) return 1 / 2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { - name: 'OUTPUT' - }, - INPUT: { - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var multi = __webpack_require__(7); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: new Float64Array(serialized[0]).buffer, - states: new Float64Array(serialized[1]).buffer, - conns: new Float64Array(serialized[2]).buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var F = [${multi.activations.toString()}]; - var cost = ${cost.toString()}; - var multi = { - deserializeDataSet: ${multi.deserializeDataSet.toString()}, - testSerializedSet: ${multi.testSerializedSet.toString()}, - activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} - }; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - var A = new Float64Array(e.data.activations); - var S = new Float64Array(e.data.states); - var data = new Float64Array(e.data.conns); - - var error = multi.testSerializedSet(set, cost, A, S, data, F); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = multi.deserializeDataSet(new Float64Array(e.data.set)); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var cp = __webpack_require__(23); -var path = __webpack_require__(11); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - this.worker = cp.fork(path.join(__dirname, '/worker')); - - this.worker.send({ set: dataSet, cost: cost.name }); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: serialized[0], - states: serialized[1], - conns: serialized[2] - }; - - var _that = this.worker; - this.worker.on('message', function callback (e) { - _that.removeListener('message', callback); - resolve(e); - }); - - this.worker.send(data); - }); - }, - - terminate: function () { - this.worker.kill(); - } -}; - - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - node: { - TestWorker: __webpack_require__(21) - }, - browser: { - TestWorker: __webpack_require__(20) - } -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_23__; - -/***/ }), -/* 24 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_24__; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(10), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); diff --git a/node_modules/neataptic/docs/cdn/1.4.3/neataptic.js b/node_modules/neataptic/docs/cdn/1.4.3/neataptic.js deleted file mode 100644 index a8c17e1..0000000 --- a/node_modules/neataptic/docs/cdn/1.4.3/neataptic.js +++ /dev/null @@ -1,4515 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("child_process"), require("os")); - else if(typeof define === 'function' && define.amd) - define(["child_process", "os"], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(require("child_process"), require("os")); - else - root["neataptic"] = factory(root["child_process"], root["os"]); -})(this, function(__WEBPACK_EXTERNAL_MODULE_23__, __WEBPACK_EXTERNAL_MODULE_24__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 25); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(17), - selection: __webpack_require__(19), - crossover: __webpack_require__(15), - cost: __webpack_require__(14), - gating: __webpack_require__(16), - connection: __webpack_require__(13), - rate: __webpack_require__(18) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Activates the node without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state); - - for (i = 0; i < this.connections.gated.length; i++) { - this.connections.gated[i].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) conn.gater.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - node.squash = methods.activation[json.squash]; - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = i < this.input ? 'input' : 'output'; - this.nodes.push(new Node(type)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - - return output; - }, - - /** - * Activates the network without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].noTraceActivate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].noTraceActivate(); - output.push(activation); - } else { - this.nodes[i].noTraceActivate(); - } - } - - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target === 'undefined' || target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden'); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var allconnections = this.connections.concat(this.selfconns); - - var connection = allconnections[Math.floor(Math.random() * allconnections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (node.connections.self.weight === 0) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost = methods.cost.MSE) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.noTraceActivate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var amount = options.amount || 1; - - var threads = options.threads; - if (typeof threads === 'undefined') { - if (typeof window === 'undefined') { // Node.js - threads = __webpack_require__(24).cpus().length; - } else { // Browser - threads = navigator.hardwareConcurrency; - } - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - if (typeof window === 'undefined') { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.node.TestWorker(converted, cost)); - } - } else { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.browser.TestWorker(converted, cost)); - } - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.selfconns = bestGenome.selfconns; - this.gates = bestGenome.gates; - - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (functionIndex === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(22), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - }, - - /** Activate a serialized network */ - activateSerializedNetwork: function (input, A, S, data, F) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - /** Deserializes a dataset to an array of arrays */ - deserializeDataSet: function (serializedSet) { - var set = []; - - var sampleSize = serializedSet[0] + serializedSet[1]; - for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) { - let input = []; - for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) { - input.push(serializedSet[j]); - } - let output = []; - for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) { - output.push(serializedSet[j]); - } - set.push(input); - set.push(output); - } - - return set; - }, - - /** A list of compiled activation functions in a certain order */ - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ] -}; - -multi.testSerializedSet = function (set, cost, A, S, data, F) { - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < set.length; i += 2) { - let output = multi.activateSerializedNetwork(set[i], A, S, data, F); - error += cost(set[i + 1], output); - } - - return error / (set.length / 2); -}; - -/* Export */ -for (var i in multi) { - module.exports[i] = multi[i]; -} - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); -var config = __webpack_require__(2); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - - this.maxNodes = options.maxNodes || Infinity; - this.maxConns = options.maxConns || Infinity; - this.maxGates = options.maxGates || Infinity; - - //allow usage of custom mutations selection method. - //the method is bound to "this" context so it can access the configured mutations list through "this.mutation" - this.mutationMethodSelect = typeof options.mutationMethodSelect == 'function' ? options.mutationMethodSelect.bind(this) : this.mutationMethodRandomSelect; - - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = undefined; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (typeof this.population[this.population.length - 1].score === 'undefined') { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = undefined; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Selects a random mutation method for a given population and ensure that maxNodes, maxConns and maxGates are not exceeded. - */ - mutationMethodRandomSelect: function(population) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - - if (mutationMethod == methods.mutation.ADD_NODE && population.nodes.length >= this.maxNodes) { - if (config.warnings) console.warn('maxNodes exceeded!'); - return null; - } - - if (mutationMethod == methods.mutation.ADD_CONN && population.connections.length >= this.maxConns) { - if (config.warnings) console.warn('maxConns exceeded!'); - return null; - } - - if (mutationMethod == methods.mutation.ADD_GATE && population.gates.length >= this.maxGates) { - if (config.warnings) console.warn('maxGates exceeded!'); - return null; - } - - - return mutationMethod; - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutationMethodSelect(this.population[i]); - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - if (this.clear) { - for (var i = 0; i < this.population.length; i++) { - this.population[i].clear(); - } - } - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - if (this.population[0].score < this.population[1].score) { - this.sort(); - } - - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) return fx; - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) return -2 * x * d; - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) return 1 / 2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { - name: 'OUTPUT' - }, - INPUT: { - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var multi = __webpack_require__(7); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: new Float64Array(serialized[0]).buffer, - states: new Float64Array(serialized[1]).buffer, - conns: new Float64Array(serialized[2]).buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var F = [${multi.activations.toString()}]; - var cost = ${cost.toString()}; - var multi = { - deserializeDataSet: ${multi.deserializeDataSet.toString()}, - testSerializedSet: ${multi.testSerializedSet.toString()}, - activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} - }; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - var A = new Float64Array(e.data.activations); - var S = new Float64Array(e.data.states); - var data = new Float64Array(e.data.conns); - - var error = multi.testSerializedSet(set, cost, A, S, data, F); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = multi.deserializeDataSet(new Float64Array(e.data.set)); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var cp = __webpack_require__(23); -var path = __webpack_require__(11); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - this.worker = cp.fork(path.join(__dirname, '/worker')); - - this.worker.send({ set: dataSet, cost: cost.name }); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: serialized[0], - states: serialized[1], - conns: serialized[2] - }; - - var _that = this.worker; - this.worker.on('message', function callback (e) { - _that.removeListener('message', callback); - resolve(e); - }); - - this.worker.send(data); - }); - }, - - terminate: function () { - this.worker.kill(); - } -}; - - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - node: { - TestWorker: __webpack_require__(21) - }, - browser: { - TestWorker: __webpack_require__(20) - } -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_23__; - -/***/ }), -/* 24 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_24__; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(10), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.4.4/neataptic.js b/node_modules/neataptic/docs/cdn/1.4.4/neataptic.js deleted file mode 100644 index a8c17e1..0000000 --- a/node_modules/neataptic/docs/cdn/1.4.4/neataptic.js +++ /dev/null @@ -1,4515 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("child_process"), require("os")); - else if(typeof define === 'function' && define.amd) - define(["child_process", "os"], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(require("child_process"), require("os")); - else - root["neataptic"] = factory(root["child_process"], root["os"]); -})(this, function(__WEBPACK_EXTERNAL_MODULE_23__, __WEBPACK_EXTERNAL_MODULE_24__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 25); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(17), - selection: __webpack_require__(19), - crossover: __webpack_require__(15), - cost: __webpack_require__(14), - gating: __webpack_require__(16), - connection: __webpack_require__(13), - rate: __webpack_require__(18) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Activates the node without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state); - - for (i = 0; i < this.connections.gated.length; i++) { - this.connections.gated[i].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) conn.gater.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - node.squash = methods.activation[json.squash]; - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = i < this.input ? 'input' : 'output'; - this.nodes.push(new Node(type)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - - return output; - }, - - /** - * Activates the network without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].noTraceActivate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].noTraceActivate(); - output.push(activation); - } else { - this.nodes[i].noTraceActivate(); - } - } - - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target === 'undefined' || target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden'); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var allconnections = this.connections.concat(this.selfconns); - - var connection = allconnections[Math.floor(Math.random() * allconnections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (node.connections.self.weight === 0) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost = methods.cost.MSE) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.noTraceActivate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var amount = options.amount || 1; - - var threads = options.threads; - if (typeof threads === 'undefined') { - if (typeof window === 'undefined') { // Node.js - threads = __webpack_require__(24).cpus().length; - } else { // Browser - threads = navigator.hardwareConcurrency; - } - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - if (typeof window === 'undefined') { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.node.TestWorker(converted, cost)); - } - } else { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.browser.TestWorker(converted, cost)); - } - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.selfconns = bestGenome.selfconns; - this.gates = bestGenome.gates; - - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (functionIndex === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(22), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - }, - - /** Activate a serialized network */ - activateSerializedNetwork: function (input, A, S, data, F) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - /** Deserializes a dataset to an array of arrays */ - deserializeDataSet: function (serializedSet) { - var set = []; - - var sampleSize = serializedSet[0] + serializedSet[1]; - for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) { - let input = []; - for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) { - input.push(serializedSet[j]); - } - let output = []; - for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) { - output.push(serializedSet[j]); - } - set.push(input); - set.push(output); - } - - return set; - }, - - /** A list of compiled activation functions in a certain order */ - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ] -}; - -multi.testSerializedSet = function (set, cost, A, S, data, F) { - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < set.length; i += 2) { - let output = multi.activateSerializedNetwork(set[i], A, S, data, F); - error += cost(set[i + 1], output); - } - - return error / (set.length / 2); -}; - -/* Export */ -for (var i in multi) { - module.exports[i] = multi[i]; -} - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); -var config = __webpack_require__(2); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - - this.maxNodes = options.maxNodes || Infinity; - this.maxConns = options.maxConns || Infinity; - this.maxGates = options.maxGates || Infinity; - - //allow usage of custom mutations selection method. - //the method is bound to "this" context so it can access the configured mutations list through "this.mutation" - this.mutationMethodSelect = typeof options.mutationMethodSelect == 'function' ? options.mutationMethodSelect.bind(this) : this.mutationMethodRandomSelect; - - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = undefined; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (typeof this.population[this.population.length - 1].score === 'undefined') { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = undefined; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Selects a random mutation method for a given population and ensure that maxNodes, maxConns and maxGates are not exceeded. - */ - mutationMethodRandomSelect: function(population) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - - if (mutationMethod == methods.mutation.ADD_NODE && population.nodes.length >= this.maxNodes) { - if (config.warnings) console.warn('maxNodes exceeded!'); - return null; - } - - if (mutationMethod == methods.mutation.ADD_CONN && population.connections.length >= this.maxConns) { - if (config.warnings) console.warn('maxConns exceeded!'); - return null; - } - - if (mutationMethod == methods.mutation.ADD_GATE && population.gates.length >= this.maxGates) { - if (config.warnings) console.warn('maxGates exceeded!'); - return null; - } - - - return mutationMethod; - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.mutationMethodSelect(this.population[i]); - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - if (this.fitnessPopulation) { - if (this.clear) { - for (var i = 0; i < this.population.length; i++) { - this.population[i].clear(); - } - } - await this.fitness(this.population); - } else { - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - if (this.population[0].score < this.population[1].score) { - this.sort(); - } - - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) return fx; - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) return -2 * x * d; - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) return 1 / 2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { - name: 'OUTPUT' - }, - INPUT: { - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var multi = __webpack_require__(7); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: new Float64Array(serialized[0]).buffer, - states: new Float64Array(serialized[1]).buffer, - conns: new Float64Array(serialized[2]).buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var F = [${multi.activations.toString()}]; - var cost = ${cost.toString()}; - var multi = { - deserializeDataSet: ${multi.deserializeDataSet.toString()}, - testSerializedSet: ${multi.testSerializedSet.toString()}, - activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} - }; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - var A = new Float64Array(e.data.activations); - var S = new Float64Array(e.data.states); - var data = new Float64Array(e.data.conns); - - var error = multi.testSerializedSet(set, cost, A, S, data, F); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = multi.deserializeDataSet(new Float64Array(e.data.set)); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var cp = __webpack_require__(23); -var path = __webpack_require__(11); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - this.worker = cp.fork(path.join(__dirname, '/worker')); - - this.worker.send({ set: dataSet, cost: cost.name }); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: serialized[0], - states: serialized[1], - conns: serialized[2] - }; - - var _that = this.worker; - this.worker.on('message', function callback (e) { - _that.removeListener('message', callback); - resolve(e); - }); - - this.worker.send(data); - }); - }, - - terminate: function () { - this.worker.kill(); - } -}; - - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - node: { - TestWorker: __webpack_require__(21) - }, - browser: { - TestWorker: __webpack_require__(20) - } -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_23__; - -/***/ }), -/* 24 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_24__; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(10), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.4.5/neataptic.js b/node_modules/neataptic/docs/cdn/1.4.5/neataptic.js deleted file mode 100644 index c18f9a6..0000000 --- a/node_modules/neataptic/docs/cdn/1.4.5/neataptic.js +++ /dev/null @@ -1,4512 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("child_process"), require("os")); - else if(typeof define === 'function' && define.amd) - define(["child_process", "os"], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(require("child_process"), require("os")); - else - root["neataptic"] = factory(root["child_process"], root["os"]); -})(this, function(__WEBPACK_EXTERNAL_MODULE_23__, __WEBPACK_EXTERNAL_MODULE_24__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) -/******/ return installedModules[moduleId].exports; -/******/ -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 25); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(9), - mutation: __webpack_require__(17), - selection: __webpack_require__(19), - crossover: __webpack_require__(15), - cost: __webpack_require__(14), - gating: __webpack_require__(16), - connection: __webpack_require__(13), - rate: __webpack_require__(18) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Activates the node without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state); - - for (i = 0; i < this.connections.gated.length; i++) { - this.connections.gated[i].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) conn.gater.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - node.squash = methods.activation[json.squash]; - - return node; -}; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(2); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(4); -var Node = __webpack_require__(1); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(7); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(2); -var Neat = __webpack_require__(8); -var Node = __webpack_require__(1); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = i < this.input ? 'input' : 'output'; - this.nodes.push(new Node(type)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - - return output; - }, - - /** - * Activates the network without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].noTraceActivate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].noTraceActivate(); - output.push(activation); - } else { - this.nodes[i].noTraceActivate(); - } - } - - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target === 'undefined' || target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden'); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var allconnections = this.connections.concat(this.selfconns); - - var connection = allconnections[Math.floor(Math.random() * allconnections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (node.connections.self.weight === 0) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost = methods.cost.MSE) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.noTraceActivate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var amount = options.amount || 1; - - var threads = options.threads; - if (typeof threads === 'undefined') { - if (typeof window === 'undefined') { // Node.js - threads = __webpack_require__(24).cpus().length; - } else { // Browser - threads = navigator.hardwareConcurrency; - } - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - if (typeof window === 'undefined') { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.node.TestWorker(converted, cost)); - } - } else { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.browser.TestWorker(converted, cost)); - } - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(genome.score) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.selfconns = bestGenome.selfconns; - this.gates = bestGenome.gates; - - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (functionIndex === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(22), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - }, - - /** Activate a serialized network */ - activateSerializedNetwork: function (input, A, S, data, F) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - /** Deserializes a dataset to an array of arrays */ - deserializeDataSet: function (serializedSet) { - var set = []; - - var sampleSize = serializedSet[0] + serializedSet[1]; - for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) { - let input = []; - for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) { - input.push(serializedSet[j]); - } - let output = []; - for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) { - output.push(serializedSet[j]); - } - set.push(input); - set.push(output); - } - - return set; - }, - - /** A list of compiled activation functions in a certain order */ - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ] -}; - -multi.testSerializedSet = function (set, cost, A, S, data, F) { - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < set.length; i += 2) { - let output = multi.activateSerializedNetwork(set[i], A, S, data, F); - error += cost(set[i + 1], output); - } - - return error / (set.length / 2); -}; - -/* Export */ -for (var i in multi) { - module.exports[i] = multi[i]; -} - - -/***/ }), -/* 8 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(6); -var methods = __webpack_require__(0); -var config = __webpack_require__(2); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - this.maxNodes = options.maxNodes || Infinity; - this.maxConns = options.maxConns || Infinity; - this.maxGates = options.maxGates || Infinity; - - // Custom mutation selection function if given - this.selectMutationMethod = typeof options.mutationSelection === 'function' ? options.mutationSelection.bind(this) : this.selectMutationMethod; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = undefined; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (typeof this.population[this.population.length - 1].score === 'undefined') { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = undefined; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Selects a random mutation method for a genome according to the parameters - */ - selectMutationMethod: function (genome) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - - if (mutationMethod === methods.mutation.ADD_NODE && genome.nodes.length >= this.maxNodes) { - if (config.warnings) console.warn('maxNodes exceeded!'); - return; - } - - if (mutationMethod === methods.mutation.ADD_CONN && genome.connections.length >= this.maxConns) { - if (config.warnings) console.warn('maxConns exceeded!'); - return; - } - - if (mutationMethod === methods.mutation.ADD_GATE && genome.gates.length >= this.maxGates) { - if (config.warnings) console.warn('maxGates exceeded!'); - return; - } - - return mutationMethod; - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.selectMutationMethod(this.population[i]); - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - var i; - if (this.fitnessPopulation) { - if (this.clear) { - for (i = 0; i < this.population.length; i++) { - this.population[i].clear(); - } - } - await this.fitness(this.population); - } else { - for (i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - if (this.population[0].score < this.population[1].score) { - this.sort(); - } - - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) return fx; - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) return -2 * x * d; - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) return 1 / 2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(6); -var Group = __webpack_require__(4); -var Layer = __webpack_require__(5); -var Node = __webpack_require__(1); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(12))) - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error / output.length; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { - name: 'OUTPUT' - }, - INPUT: { - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(9); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var multi = __webpack_require__(7); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: new Float64Array(serialized[0]).buffer, - states: new Float64Array(serialized[1]).buffer, - conns: new Float64Array(serialized[2]).buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var F = [${multi.activations.toString()}]; - var cost = ${cost.toString()}; - var multi = { - deserializeDataSet: ${multi.deserializeDataSet.toString()}, - testSerializedSet: ${multi.testSerializedSet.toString()}, - activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} - }; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - var A = new Float64Array(e.data.activations); - var S = new Float64Array(e.data.states); - var data = new Float64Array(e.data.conns); - - var error = multi.testSerializedSet(set, cost, A, S, data, F); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = multi.deserializeDataSet(new Float64Array(e.data.set)); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var cp = __webpack_require__(23); -var path = __webpack_require__(11); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - this.worker = cp.fork(path.join(__dirname, '/worker')); - - this.worker.send({ set: dataSet, cost: cost.name }); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: serialized[0], - states: serialized[1], - conns: serialized[2] - }; - - var _that = this.worker; - this.worker.on('message', function callback (e) { - _that.removeListener('message', callback); - resolve(e); - }); - - this.worker.send(data); - }); - }, - - terminate: function () { - this.worker.kill(); - } -}; - - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - node: { - TestWorker: __webpack_require__(21) - }, - browser: { - TestWorker: __webpack_require__(20) - } -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_23__; - -/***/ }), -/* 24 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_24__; - -/***/ }), -/* 25 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(10), - Network: __webpack_require__(6), - config: __webpack_require__(2), - Group: __webpack_require__(4), - Layer: __webpack_require__(5), - Node: __webpack_require__(1), - Neat: __webpack_require__(8), - multi: __webpack_require__(7) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.4.6/neataptic.js b/node_modules/neataptic/docs/cdn/1.4.6/neataptic.js deleted file mode 100644 index 3151b5b..0000000 --- a/node_modules/neataptic/docs/cdn/1.4.6/neataptic.js +++ /dev/null @@ -1,4509 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("child_process"), require("os")); - else if(typeof define === 'function' && define.amd) - define(["child_process", "os"], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(require("child_process"), require("os")); - else - root["neataptic"] = factory(root["child_process"], root["os"]); -})(this, function(__WEBPACK_EXTERNAL_MODULE_21__, __WEBPACK_EXTERNAL_MODULE_25__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 10); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(8), - mutation: __webpack_require__(11), - selection: __webpack_require__(12), - crossover: __webpack_require__(13), - cost: __webpack_require__(14), - gating: __webpack_require__(15), - connection: __webpack_require__(16), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(1); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Activates the node without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state); - - for (i = 0; i < this.connections.gated.length; i++) { - this.connections.gated[i].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) conn.gater.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - node.squash = methods.activation[json.squash]; - - return node; -}; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(5); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(1); -var Neat = __webpack_require__(9); -var Node = __webpack_require__(2); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = i < this.input ? 'input' : 'output'; - this.nodes.push(new Node(type)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - - return output; - }, - - /** - * Activates the network without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].noTraceActivate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].noTraceActivate(); - output.push(activation); - } else { - this.nodes[i].noTraceActivate(); - } - } - - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target === 'undefined' || target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden'); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var allconnections = this.connections.concat(this.selfconns); - - var connection = allconnections[Math.floor(Math.random() * allconnections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (node.connections.self.weight === 0) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost = methods.cost.MSE) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.noTraceActivate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var amount = options.amount || 1; - - var threads = options.threads; - if (typeof threads === 'undefined') { - if (typeof window === 'undefined') { // Node.js - threads = __webpack_require__(25).cpus().length; - } else { // Browser - threads = navigator.hardwareConcurrency; - } - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - if (typeof window === 'undefined') { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.node.TestWorker(converted, cost)); - } - } else { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.browser.TestWorker(converted, cost)); - } - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(parseFloat(result)) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.selfconns = bestGenome.selfconns; - this.gates = bestGenome.gates; - - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (functionIndex === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - }, - - /** Activate a serialized network */ - activateSerializedNetwork: function (input, A, S, data, F) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - /** Deserializes a dataset to an array of arrays */ - deserializeDataSet: function (serializedSet) { - var set = []; - - var sampleSize = serializedSet[0] + serializedSet[1]; - for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) { - let input = []; - for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) { - input.push(serializedSet[j]); - } - let output = []; - for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) { - output.push(serializedSet[j]); - } - set.push(input); - set.push(output); - } - - return set; - }, - - /** A list of compiled activation functions in a certain order */ - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ] -}; - -multi.testSerializedSet = function (set, cost, A, S, data, F) { - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < set.length; i += 2) { - let output = multi.activateSerializedNetwork(set[i], A, S, data, F); - error += cost(set[i + 1], output); - } - - return error / (set.length / 2); -}; - -/* Export */ -for (var i in multi) { - module.exports[i] = multi[i]; -} - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(1); -var Layer = __webpack_require__(7); -var Node = __webpack_require__(2); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum, true); - } else { - this.nodes[i].propagate(rate, momentum, true, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(6); -var Node = __webpack_require__(2); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum); - } else { - this.nodes[i].propagate(rate, momentum, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) return fx; - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) return -2 * x * d; - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) return 1 / 2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(4); -var methods = __webpack_require__(0); -var config = __webpack_require__(1); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - this.maxNodes = options.maxNodes || Infinity; - this.maxConns = options.maxConns || Infinity; - this.maxGates = options.maxGates || Infinity; - - // Custom mutation selection function if given - this.selectMutationMethod = typeof options.mutationSelection === 'function' ? options.mutationSelection.bind(this) : this.selectMutationMethod; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = undefined; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (typeof this.population[this.population.length - 1].score === 'undefined') { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = undefined; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Selects a random mutation method for a genome according to the parameters - */ - selectMutationMethod: function (genome) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - - if (mutationMethod === methods.mutation.ADD_NODE && genome.nodes.length >= this.maxNodes) { - if (config.warnings) console.warn('maxNodes exceeded!'); - return; - } - - if (mutationMethod === methods.mutation.ADD_CONN && genome.connections.length >= this.maxConns) { - if (config.warnings) console.warn('maxConns exceeded!'); - return; - } - - if (mutationMethod === methods.mutation.ADD_GATE && genome.gates.length >= this.maxGates) { - if (config.warnings) console.warn('maxGates exceeded!'); - return; - } - - return mutationMethod; - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.selectMutationMethod(this.population[i]); - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - var i; - if (this.fitnessPopulation) { - if (this.clear) { - for (i = 0; i < this.population.length; i++) { - this.population[i].clear(); - } - } - await this.fitness(this.population); - } else { - for (i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - if (this.population[0].score < this.population[1].score) { - this.sort(); - } - - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(18), - Network: __webpack_require__(4), - config: __webpack_require__(1), - Group: __webpack_require__(6), - Layer: __webpack_require__(7), - Node: __webpack_require__(2), - Neat: __webpack_require__(9), - multi: __webpack_require__(5) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(8); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error / output.length; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { - name: 'OUTPUT' - }, - INPUT: { - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(4); -var Group = __webpack_require__(6); -var Layer = __webpack_require__(7); -var Node = __webpack_require__(2); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - node: { - TestWorker: __webpack_require__(20) - }, - browser: { - TestWorker: __webpack_require__(24) - } -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var cp = __webpack_require__(21); -var path = __webpack_require__(22); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - this.worker = cp.fork(path.join(__dirname, '/worker')); - - this.worker.send({ set: dataSet, cost: cost.name }); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: serialized[0], - states: serialized[1], - conns: serialized[2] - }; - - var _that = this.worker; - this.worker.on('message', function callback (e) { - _that.removeListener('message', callback); - resolve(e); - }); - - this.worker.send(data); - }); - }, - - terminate: function () { - this.worker.kill(); - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_21__; - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(23))) - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var multi = __webpack_require__(5); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: new Float64Array(serialized[0]).buffer, - states: new Float64Array(serialized[1]).buffer, - conns: new Float64Array(serialized[2]).buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var F = [${multi.activations.toString()}]; - var cost = ${cost.toString()}; - var multi = { - deserializeDataSet: ${multi.deserializeDataSet.toString()}, - testSerializedSet: ${multi.testSerializedSet.toString()}, - activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} - }; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - var A = new Float64Array(e.data.activations); - var S = new Float64Array(e.data.states); - var data = new Float64Array(e.data.conns); - - var error = multi.testSerializedSet(set, cost, A, S, data, F); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = multi.deserializeDataSet(new Float64Array(e.data.set)); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 25 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_25__; - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/cdn/1.4.7/neataptic.js b/node_modules/neataptic/docs/cdn/1.4.7/neataptic.js deleted file mode 100644 index b1eb7de..0000000 --- a/node_modules/neataptic/docs/cdn/1.4.7/neataptic.js +++ /dev/null @@ -1,4509 +0,0 @@ -/*! - * The MIT License (MIT) - * - * Copyright 2017 Thomas Wagenaar . Copyright for - * portions of Neataptic are held by Copyright 2017 Juan Cazala - cazala.com, as a - * part of project Synaptic. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE - * - */ -(function webpackUniversalModuleDefinition(root, factory) { - if(typeof exports === 'object' && typeof module === 'object') - module.exports = factory(require("child_process"), require("os")); - else if(typeof define === 'function' && define.amd) - define(["child_process", "os"], factory); - else if(typeof exports === 'object') - exports["neataptic"] = factory(require("child_process"), require("os")); - else - root["neataptic"] = factory(root["child_process"], root["os"]); -})(this, function(__WEBPACK_EXTERNAL_MODULE_21__, __WEBPACK_EXTERNAL_MODULE_25__) { -return /******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = ""; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 10); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - METHODS -*******************************************************************************/ - -var methods = { - activation: __webpack_require__(8), - mutation: __webpack_require__(11), - selection: __webpack_require__(12), - crossover: __webpack_require__(13), - cost: __webpack_require__(14), - gating: __webpack_require__(15), - connection: __webpack_require__(16), - rate: __webpack_require__(17) -}; - -/** Export */ -module.exports = methods; - - -/***/ }), -/* 1 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONFIG -*******************************************************************************/ - -// Config -var config = { - warnings: false -}; - -/* Export */ -module.exports = config; - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Node; - -/* Import */ -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(1); - -/******************************************************************************* - NODE -*******************************************************************************/ - -function Node (type) { - this.bias = (type === 'input') ? 0 : Math.random() * 0.2 - 0.1; - this.squash = methods.activation.LOGISTIC; - this.type = type || 'hidden'; - - this.activation = 0; - this.state = 0; - this.old = 0; - - // For dropout - this.mask = 1; - - // For tracking momentum - this.previousDeltaBias = 0; - - // Batch training - this.totalDeltaBias = 0; - - this.connections = { - in: [], - out: [], - gated: [], - self: new Connection(this, this, 0) - }; - - // Data for backpropagation - this.error = { - responsibility: 0, - projected: 0, - gated: 0 - }; -} - -Node.prototype = { - /** - * Activates the node - */ - activate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - this.old = this.state; - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state) * this.mask; - this.derivative = this.squash(this.state, true); - - // Update traces - var nodes = []; - var influences = []; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - - let index = nodes.indexOf(node); - if (index > -1) { - influences[index] += conn.weight * conn.from.activation; - } else { - nodes.push(node); - influences.push(conn.weight * conn.from.activation + - (node.connections.self.gater === this ? node.old : 0)); - } - - // Adjust the gain to this nodes' activation - conn.gain = this.activation; - } - - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - // Elegibility trace - connection.elegibility = this.connections.self.gain * this.connections.self.weight * - connection.elegibility + connection.from.activation * connection.gain; - - // Extended trace - for (var j = 0; j < nodes.length; j++) { - let node = nodes[j]; - let influence = influences[j]; - - let index = connection.xtrace.nodes.indexOf(node); - - if (index > -1) { - connection.xtrace.values[index] = node.connections.self.gain * node.connections.self.weight * - connection.xtrace.values[index] + this.derivative * connection.elegibility * influence; - } else { - // Does not exist there yet, might be through mutation - connection.xtrace.nodes.push(node); - connection.xtrace.values.push(this.derivative * connection.elegibility * influence); - } - } - } - - return this.activation; - }, - - /** - * Activates the node without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - // Check if an input is given - if (typeof input !== 'undefined') { - this.activation = input; - return this.activation; - } - - // All activation sources coming from the node itself - this.state = this.connections.self.gain * this.connections.self.weight * this.state + this.bias; - - // Activation sources coming from connections - var i; - for (i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - this.state += connection.from.activation * connection.weight * connection.gain; - } - - // Squash the values received - this.activation = this.squash(this.state); - - for (i = 0; i < this.connections.gated.length; i++) { - this.connections.gated[i].gain = this.activation; - } - - return this.activation; - }, - - /** - * Back-propagate the error, aka learn - */ - propagate: function (rate, momentum, update, target) { - momentum = momentum || 0; - rate = rate || 0.3; - - // Error accumulator - var error = 0; - - // Output nodes get their error from the enviroment - if (this.type === 'output') { - this.error.responsibility = this.error.projected = target - this.activation; - } else { // the rest of the nodes compute their error responsibilities by backpropagation - // error responsibilities from all the connections projected from this node - var i; - for (i = 0; i < this.connections.out.length; i++) { - let connection = this.connections.out[i]; - let node = connection.to; - // Eq. 21 - error += node.error.responsibility * connection.weight * connection.gain; - } - - // Projected error responsibility - this.error.projected = this.derivative * error; - - // Error responsibilities from all connections gated by this neuron - error = 0; - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - let node = conn.to; - let influence = node.connections.self.gater === this ? node.old : 0; - - influence += conn.weight * conn.from.activation; - error += node.error.responsibility * influence; - } - - // Gated error responsibility - this.error.gated = this.derivative * error; - - // Error responsibility - this.error.responsibility = this.error.projected + this.error.gated; - } - - if (this.type === 'constant') return; - - // Adjust all the node's incoming connections - for (i = 0; i < this.connections.in.length; i++) { - let connection = this.connections.in[i]; - - let gradient = this.error.projected * connection.elegibility; - - for (var j = 0; j < connection.xtrace.nodes.length; j++) { - let node = connection.xtrace.nodes[j]; - let value = connection.xtrace.values[j]; - gradient += node.error.responsibility * value; - } - - // Adjust weight - let deltaWeight = rate * gradient * this.mask; - connection.totalDeltaWeight += deltaWeight; - if (update) { - connection.totalDeltaWeight += momentum * connection.previousDeltaWeight; - connection.weight += connection.totalDeltaWeight; - connection.previousDeltaWeight = connection.totalDeltaWeight; - connection.totalDeltaWeight = 0; - } - } - - // Adjust bias - var deltaBias = rate * this.error.responsibility; - this.totalDeltaBias += deltaBias; - if (update) { - this.totalDeltaBias += momentum * this.previousDeltaBias; - this.bias += this.totalDeltaBias; - this.previousDeltaBias = this.totalDeltaBias; - this.totalDeltaBias = 0; - } - }, - - /** - * Creates a connection from this node to the given node - */ - connect: function (target, weight) { - var connections = []; - if (typeof target.bias !== 'undefined') { // must be a node! - if (target === this) { - // Turn on the self connection by setting the weight - if (this.connections.self.weight !== 0) { - if (config.warnings) console.warn('This connection already exists!'); - } else { - this.connections.self.weight = weight || 1; - } - connections.push(this.connections.self); - } else if (this.isProjectingTo(target)) { - throw new Error('Already projecting a connection to this node!'); - } else { - let connection = new Connection(this, target, weight); - target.connections.in.push(connection); - this.connections.out.push(connection); - - connections.push(connection); - } - } else { // should be a group - for (var i = 0; i < target.nodes.length; i++) { - let connection = new Connection(this, target.nodes[i], weight); - target.nodes[i].connections.in.push(connection); - this.connections.out.push(connection); - target.connections.in.push(connection); - - connections.push(connection); - } - } - return connections; - }, - - /** - * Disconnects this node from the other node - */ - disconnect: function (node, twosided) { - if (this === node) { - this.connections.self.weight = 0; - return; - } - - for (var i = 0; i < this.connections.out.length; i++) { - let conn = this.connections.out[i]; - if (conn.to === node) { - this.connections.out.splice(i, 1); - let j = conn.to.connections.in.indexOf(conn); - conn.to.connections.in.splice(j, 1); - if (conn.gater !== null) conn.gater.ungate(conn); - break; - } - } - - if (twosided) { - node.disconnect(this); - } - }, - - /** - * Make this node gate a connection - */ - gate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - - this.connections.gated.push(connection); - connection.gater = this; - } - }, - - /** - * Removes the gates from this node from the given connection(s) - */ - ungate: function (connections) { - if (!Array.isArray(connections)) { - connections = [connections]; - } - - for (var i = connections.length - 1; i >= 0; i--) { - var connection = connections[i]; - - var index = this.connections.gated.indexOf(connection); - this.connections.gated.splice(index, 1); - connection.gater = null; - connection.gain = 1; - } - }, - - /** - * Clear the context of the node - */ - clear: function () { - for (var i = 0; i < this.connections.in.length; i++) { - var connection = this.connections.in[i]; - - connection.elegibility = 0; - connection.xtrace = { - nodes: [], - values: [] - }; - } - - for (i = 0; i < this.connections.gated.length; i++) { - let conn = this.connections.gated[i]; - conn.gain = 0; - } - - this.error.responsibility = this.error.projected = this.error.gated = 0; - this.old = this.state = this.activation = 0; - }, - - /** - * Mutates the node with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No mutate method given!'); - } else if (!(method.name in methods.mutation)) { - throw new Error('This method does not exist!'); - } - - switch (method) { - case methods.mutation.MOD_ACTIVATION: - // Can't be the same squash - var squash = method.allowed[(method.allowed.indexOf(this.squash) + Math.floor(Math.random() * (method.allowed.length - 1)) + 1) % method.allowed.length]; - this.squash = squash; - break; - case methods.mutation.MOD_BIAS: - var modification = Math.random() * (method.max - method.min) + method.min; - this.bias += modification; - break; - } - }, - - /** - * Checks if this node is projecting to the given node - */ - isProjectingTo: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.out.length; i++) { - var conn = this.connections.out[i]; - if (conn.to === node) { - return true; - } - } - return false; - }, - - /** - * Checks if the given node is projecting to this node - */ - isProjectedBy: function (node) { - if (node === this && this.connections.self.weight !== 0) return true; - - for (var i = 0; i < this.connections.in.length; i++) { - var conn = this.connections.in[i]; - if (conn.from === node) { - return true; - } - } - - return false; - }, - - /** - * Converts the node to a json object - */ - toJSON: function () { - var json = { - bias: this.bias, - type: this.type, - squash: this.squash.name, - mask: this.mask - }; - - return json; - } -}; - -/** - * Convert a json object to a node - */ -Node.fromJSON = function (json) { - var node = new Node(); - node.bias = json.bias; - node.type = json.type; - node.mask = json.mask; - node.squash = methods.activation[json.squash]; - - return node; -}; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports) { - -/* Export */ -module.exports = Connection; - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -function Connection (from, to, weight) { - this.from = from; - this.to = to; - this.gain = 1; - - this.weight = (typeof weight === 'undefined') ? Math.random() * 0.2 - 0.1 : weight; - - this.gater = null; - this.elegibility = 0; - - // For tracking momentum - this.previousDeltaWeight = 0; - - // Batch training - this.totalDeltaWeight = 0; - - this.xtrace = { - nodes: [], - values: [] - }; -} - -Connection.prototype = { - /** - * Converts the connection to a json object - */ - toJSON: function () { - var json = { - weight: this.weight - }; - - return json; - } -}; - -/** - * Returns an innovation ID - * https://en.wikipedia.org/wiki/Pairing_function (Cantor pairing function) - */ -Connection.innovationID = function (a, b) { - return 1 / 2 * (a + b) * (a + b + 1) + b; -}; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Network; - -/* Import */ -var multi = __webpack_require__(5); -var methods = __webpack_require__(0); -var Connection = __webpack_require__(3); -var config = __webpack_require__(1); -var Neat = __webpack_require__(9); -var Node = __webpack_require__(2); - -/* Easier variable naming */ -var mutation = methods.mutation; - -/******************************************************************************* - NETWORK -*******************************************************************************/ - -function Network (input, output) { - if (typeof input === 'undefined' || typeof output === 'undefined') { - throw new Error('No input or output size given'); - } - - this.input = input; - this.output = output; - - // Store all the node and connection genes - this.nodes = []; // Stored in activation order - this.connections = []; - this.gates = []; - this.selfconns = []; - - // Regularization - this.dropout = 0; - - // Create input and output nodes - var i; - for (i = 0; i < this.input + this.output; i++) { - var type = i < this.input ? 'input' : 'output'; - this.nodes.push(new Node(type)); - } - - // Connect input nodes with output nodes directly - for (i = 0; i < this.input; i++) { - for (var j = this.input; j < this.output + this.input; j++) { - // https://stats.stackexchange.com/a/248040/147931 - var weight = Math.random() * this.input * Math.sqrt(2 / this.input); - this.connect(this.nodes[i], this.nodes[j], weight); - } - } -} - -Network.prototype = { - /** - * Activates the network - */ - activate: function (input, training) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].activate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].activate(); - output.push(activation); - } else { - if (training) this.nodes[i].mask = Math.random() < this.dropout ? 0 : 1; - this.nodes[i].activate(); - } - } - - return output; - }, - - /** - * Activates the network without calculating elegibility traces and such - */ - noTraceActivate: function (input) { - var output = []; - - // Activate nodes chronologically - for (var i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'input') { - this.nodes[i].noTraceActivate(input[i]); - } else if (this.nodes[i].type === 'output') { - var activation = this.nodes[i].noTraceActivate(); - output.push(activation); - } else { - this.nodes[i].noTraceActivate(); - } - } - - return output; - }, - - /** - * Backpropagate the network - */ - propagate: function (rate, momentum, update, target) { - if (typeof target === 'undefined' || target.length !== this.output) { - throw new Error('Output target length should match network output length'); - } - - var targetIndex = target.length; - - // Propagate output nodes - var i; - for (i = this.nodes.length - 1; i >= this.nodes.length - this.output; i--) { - this.nodes[i].propagate(rate, momentum, update, target[--targetIndex]); - } - - // Propagate hidden and input nodes - for (i = this.nodes.length - this.output - 1; i >= this.input; i--) { - this.nodes[i].propagate(rate, momentum, update); - } - }, - - /** - * Clear the context of the network - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - }, - - /** - * Connects the from node to the to node - */ - connect: function (from, to, weight) { - var connections = from.connect(to, weight); - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (from !== to) { - this.connections.push(connection); - } else { - this.selfconns.push(connection); - } - } - - return connections; - }, - - /** - * Disconnects the from node from the to node - */ - disconnect: function (from, to) { - // Delete the connection in the network's connection array - var connections = from === to ? this.selfconns : this.connections; - - for (var i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.from === from && connection.to === to) { - if (connection.gater !== null) this.ungate(connection); - connections.splice(i, 1); - break; - } - } - - // Delete the connection at the sending and receiving neuron - from.disconnect(to); - }, - - /** - * Gate a connection with a node - */ - gate: function (node, connection) { - if (this.nodes.indexOf(node) === -1) { - throw new Error('This node is not part of the network!'); - } else if (connection.gater != null) { - if (config.warnings) console.warn('This connection is already gated!'); - return; - } - node.gate(connection); - this.gates.push(connection); - }, - - /** - * Remove the gate of a connection - */ - ungate: function (connection) { - var index = this.gates.indexOf(connection); - if (index === -1) { - throw new Error('This connection is not gated!'); - } - - this.gates.splice(index, 1); - connection.gater.ungate(connection); - }, - - /** - * Removes a node from the network - */ - remove: function (node) { - var index = this.nodes.indexOf(node); - - if (index === -1) { - throw new Error('This node does not exist in the network!'); - } - - // Keep track of gaters - var gaters = []; - - // Remove selfconnections from this.selfconns - this.disconnect(node, node); - - // Get all its inputting nodes - var inputs = []; - for (var i = node.connections.in.length - 1; i >= 0; i--) { - let connection = node.connections.in[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - inputs.push(connection.from); - this.disconnect(connection.from, node); - } - - // Get all its outputing nodes - var outputs = []; - for (i = node.connections.out.length - 1; i >= 0; i--) { - let connection = node.connections.out[i]; - if (mutation.SUB_NODE.keep_gates && connection.gater !== null && connection.gater !== node) { - gaters.push(connection.gater); - } - outputs.push(connection.to); - this.disconnect(node, connection.to); - } - - // Connect the input nodes to the output nodes (if not already connected) - var connections = []; - for (i = 0; i < inputs.length; i++) { - let input = inputs[i]; - for (var j = 0; j < outputs.length; j++) { - let output = outputs[j]; - if (!input.isProjectingTo(output)) { - var conn = this.connect(input, output); - connections.push(conn[0]); - } - } - } - - // Gate random connections with gaters - for (i = 0; i < gaters.length; i++) { - if (connections.length === 0) break; - - let gater = gaters[i]; - let connIndex = Math.floor(Math.random() * connections.length); - - this.gate(gater, connections[connIndex]); - connections.splice(connIndex, 1); - } - - // Remove gated connections gated by this node - for (i = node.connections.gated.length - 1; i >= 0; i--) { - let conn = node.connections.gated[i]; - this.ungate(conn); - } - - // Remove selfconnection - this.disconnect(node, node); - - // Remove the node from this.nodes - this.nodes.splice(index, 1); - }, - - /** - * Mutates the network with the given method - */ - mutate: function (method) { - if (typeof method === 'undefined') { - throw new Error('No (correct) mutate method given!'); - } - - var i, j; - switch (method) { - case mutation.ADD_NODE: - // Look for an existing connection and place a node in between - var connection = this.connections[Math.floor(Math.random() * this.connections.length)]; - var gater = connection.gater; - this.disconnect(connection.from, connection.to); - - // Insert the new node right before the old connection.to - var toIndex = this.nodes.indexOf(connection.to); - var node = new Node('hidden'); - - // Random squash function - node.mutate(mutation.MOD_ACTIVATION); - - // Place it in this.nodes - var minBound = Math.min(toIndex, this.nodes.length - this.output); - this.nodes.splice(minBound, 0, node); - - // Now create two new connections - var newConn1 = this.connect(connection.from, node)[0]; - var newConn2 = this.connect(node, connection.to)[0]; - - // Check if the original connection was gated - if (gater != null) { - this.gate(gater, Math.random() >= 0.5 ? newConn1 : newConn2); - } - break; - case mutation.SUB_NODE: - // Check if there are nodes left to remove - if (this.nodes.length === this.input + this.output) { - if (config.warnings) console.warn('No more nodes left to remove!'); - break; - } - - // Select a node which isn't an input or output node - var index = Math.floor(Math.random() * (this.nodes.length - this.output - this.input) + this.input); - this.remove(this.nodes[index]); - break; - case mutation.ADD_CONN: - // Create an array of all uncreated (feedforward) connections - var available = []; - for (i = 0; i < this.nodes.length - this.output; i++) { - let node1 = this.nodes[i]; - for (j = Math.max(i + 1, this.input); j < this.nodes.length; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.to) > this.nodes.indexOf(conn.from)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.MOD_WEIGHT: - var allconnections = this.connections.concat(this.selfconns); - - var connection = allconnections[Math.floor(Math.random() * allconnections.length)]; - var modification = Math.random() * (method.max - method.min) + method.min; - connection.weight += modification; - break; - case mutation.MOD_BIAS: - // Has no effect on input node, so they are excluded - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - node.mutate(method); - break; - case mutation.MOD_ACTIVATION: - // Has no effect on input node, so they are excluded - if (!method.mutateOutput && this.input + this.output === this.nodes.length) { - if (config.warnings) console.warn('No nodes that allow mutation of activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node = this.nodes[index]; - - node.mutate(method); - break; - case mutation.ADD_SELF_CONN: - // Check which nodes aren't selfconnected yet - var possible = []; - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - if (node.connections.self.weight === 0) { - possible.push(node); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more self-connections to add!'); - break; - } - - // Select a random node - var node = possible[Math.floor(Math.random() * possible.length)]; - - // Connect it to himself - this.connect(node, node); - break; - case mutation.SUB_SELF_CONN: - if (this.selfconns.length === 0) { - if (config.warnings) console.warn('No more self-connections to remove!'); - break; - } - var conn = this.selfconns[Math.floor(Math.random() * this.selfconns.length)]; - this.disconnect(conn.from, conn.to); - break; - case mutation.ADD_GATE: - var allconnections = this.connections.concat(this.selfconns); - - // Create a list of all non-gated connections - var possible = []; - for (i = 0; i < allconnections.length; i++) { - let conn = allconnections[i]; - if (conn.gater === null) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No more connections to gate!'); - break; - } - - // Select a random gater node and connection, can't be gated by input - var index = Math.floor(Math.random() * (this.nodes.length - this.input) + this.input); - var node = this.nodes[index]; - var conn = possible[Math.floor(Math.random() * possible.length)]; - - // Gate the connection with the node - this.gate(node, conn); - break; - case mutation.SUB_GATE: - // Select a random gated connection - if (this.gates.length === 0) { - if (config.warnings) console.warn('No more connections to ungate!'); - break; - } - - var index = Math.floor(Math.random() * this.gates.length); - var gatedconn = this.gates[index]; - - this.ungate(gatedconn); - break; - case mutation.ADD_BACK_CONN: - // Create an array of all uncreated (backfed) connections - var available = []; - for (i = this.input; i < this.nodes.length; i++) { - let node1 = this.nodes[i]; - for (j = this.input; j < i; j++) { - let node2 = this.nodes[j]; - if (!node1.isProjectingTo(node2)) available.push([node1, node2]); - } - } - - if (available.length === 0) { - if (config.warnings) console.warn('No more connections to be made!'); - break; - } - - var pair = available[Math.floor(Math.random() * available.length)]; - this.connect(pair[0], pair[1]); - break; - case mutation.SUB_BACK_CONN: - // List of possible connections that can be removed - var possible = []; - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - // Check if it is not disabling a node - if (conn.from.connections.out.length > 1 && conn.to.connections.in.length > 1 && this.nodes.indexOf(conn.from) > this.nodes.indexOf(conn.to)) { - possible.push(conn); - } - } - - if (possible.length === 0) { - if (config.warnings) console.warn('No connections to remove!'); - break; - } - - var randomConn = possible[Math.floor(Math.random() * possible.length)]; - this.disconnect(randomConn.from, randomConn.to); - break; - case mutation.SWAP_NODES: - // Has no effect on input node, so they are excluded - if ((method.mutateOutput && this.nodes.length - this.input < 2) || - (!method.mutateOutput && this.nodes.length - this.input - this.output < 2)) { - if (config.warnings) console.warn('No nodes that allow swapping of bias and activation function'); - break; - } - - var index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node1 = this.nodes[index]; - index = Math.floor(Math.random() * (this.nodes.length - (method.mutateOutput ? 0 : this.output) - this.input) + this.input); - var node2 = this.nodes[index]; - - var biasTemp = node1.bias; - var squashTemp = node1.squash; - - node1.bias = node2.bias; - node1.squash = node2.squash; - node2.bias = biasTemp; - node2.squash = squashTemp; - break; - } - }, - - /** - * Train the given set to this network - */ - train: function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - options = options || {}; - - // Warning messages - if (typeof options.rate === 'undefined') { - if (config.warnings) console.warn('Using default learning rate, please define a rate!'); - } - if (typeof options.iterations === 'undefined') { - if (config.warnings) console.warn('No target iterations given, running until error is reached!'); - } - - // Read the options - var targetError = options.error || 0.05; - var cost = options.cost || methods.cost.MSE; - var baseRate = options.rate || 0.3; - var dropout = options.dropout || 0; - var momentum = options.momentum || 0; - var batchSize = options.batchSize || 1; // online learning - var ratePolicy = options.ratePolicy || methods.rate.FIXED(); - - var start = Date.now(); - - if (batchSize > set.length) { - throw new Error('Batch size must be smaller or equal to dataset length!'); - } else if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - // Save to network - this.dropout = dropout; - - if (options.crossValidate) { - let numTrain = Math.ceil((1 - options.crossValidate.testSize) * set.length); - var trainSet = set.slice(0, numTrain); - var testSet = set.slice(numTrain); - } - - // Loops the training process - var currentRate = baseRate; - var iteration = 0; - var error = 1; - - var i, j, x; - while (error > targetError && (options.iterations === 0 || iteration < options.iterations)) { - if (options.crossValidate && error <= options.crossValidate.testError) break; - - iteration++; - - // Update the rate - currentRate = ratePolicy(baseRate, iteration); - - // Checks if cross validation is enabled - if (options.crossValidate) { - this._trainSet(trainSet, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - error = this.test(testSet, cost).error; - if (options.clear) this.clear(); - } else { - error = this._trainSet(set, batchSize, currentRate, momentum, cost); - if (options.clear) this.clear(); - } - - // Checks for options such as scheduled logs and shuffling - if (options.shuffle) { - for (j, x, i = set.length; i; j = Math.floor(Math.random() * i), x = set[--i], set[i] = set[j], set[j] = x); - } - - if (options.log && iteration % options.log === 0) { - console.log('iteration', iteration, 'error', error, 'rate', currentRate); - } - - if (options.schedule && iteration % options.schedule.iterations === 0) { - options.schedule.function({ error: error, iteration: iteration }); - } - } - - if (options.clear) this.clear(); - - if (dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - return { - error: error, - iterations: iteration, - time: Date.now() - start - }; - }, - - /** - * Performs one training epoch and returns the error - * private function used in this.train - */ - _trainSet: function (set, batchSize, currentRate, momentum, costFunction) { - var errorSum = 0; - for (var i = 0; i < set.length; i++) { - var input = set[i].input; - var target = set[i].output; - - var update = !!((i + 1) % batchSize === 0 || (i + 1) === set.length); - - var output = this.activate(input, true); - this.propagate(currentRate, momentum, update, target); - - errorSum += costFunction(target, output); - } - return errorSum / set.length; - }, - - /** - * Tests a set and returns the error and elapsed time - */ - test: function (set, cost = methods.cost.MSE) { - // Check if dropout is enabled, set correct mask - var i; - if (this.dropout) { - for (i = 0; i < this.nodes.length; i++) { - if (this.nodes[i].type === 'hidden' || this.nodes[i].type === 'constant') { - this.nodes[i].mask = 1 - this.dropout; - } - } - } - - var error = 0; - var start = Date.now(); - - for (i = 0; i < set.length; i++) { - let input = set[i].input; - let target = set[i].output; - let output = this.noTraceActivate(input); - error += cost(target, output); - } - - error /= set.length; - - var results = { - error: error, - time: Date.now() - start - }; - - return results; - }, - - /** - * Creates a json that can be used to create a graph with d3 and webcola - */ - graph: function (width, height) { - var input = 0; - var output = 0; - - var json = { - nodes: [], - links: [], - constraints: [{ - type: 'alignment', - axis: 'x', - offsets: [] - }, { - type: 'alignment', - axis: 'y', - offsets: [] - }] - }; - - var i; - for (i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node.type === 'input') { - if (this.input === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.input - 1) * input++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: 0 - }); - } else if (node.type === 'output') { - if (this.output === 1) { - json.constraints[0].offsets.push({ - node: i, - offset: 0 - }); - } else { - json.constraints[0].offsets.push({ - node: i, - offset: 0.8 * width / (this.output - 1) * output++ - }); - } - json.constraints[1].offsets.push({ - node: i, - offset: -0.8 * height - }); - } - - json.nodes.push({ - id: i, - name: node.type === 'hidden' ? node.squash.name : node.type.toUpperCase(), - activation: node.activation, - bias: node.bias - }); - } - - var connections = this.connections.concat(this.selfconns); - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (connection.gater == null) { - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: this.nodes.indexOf(connection.to), - weight: connection.weight - }); - } else { - // Add a gater 'node' - var index = json.nodes.length; - json.nodes.push({ - id: index, - activation: connection.gater.activation, - name: 'GATE' - }); - json.links.push({ - source: this.nodes.indexOf(connection.from), - target: index, - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: index, - target: this.nodes.indexOf(connection.to), - weight: 1 / 2 * connection.weight - }); - json.links.push({ - source: this.nodes.indexOf(connection.gater), - target: index, - weight: connection.gater.activation, - gate: true - }); - } - } - - return json; - }, - - /** - * Convert the network to a json object - */ - toJSON: function () { - var json = { - nodes: [], - connections: [], - input: this.input, - output: this.output, - dropout: this.dropout - }; - - // So we don't have to use expensive .indexOf() - var i; - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - let tojson = node.toJSON(); - tojson.index = i; - json.nodes.push(tojson); - - if (node.connections.self.weight !== 0) { - let tojson = node.connections.self.toJSON(); - tojson.from = i; - tojson.to = i; - - tojson.gater = node.connections.self.gater != null ? node.connections.self.gater.index : null; - json.connections.push(tojson); - } - } - - for (i = 0; i < this.connections.length; i++) { - let conn = this.connections[i]; - let tojson = conn.toJSON(); - tojson.from = conn.from.index; - tojson.to = conn.to.index; - - tojson.gater = conn.gater != null ? conn.gater.index : null; - - json.connections.push(tojson); - } - - return json; - }, - - /** - * Sets the value of a property for every node in this network - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].bias = values.bias || this.nodes[i].bias; - this.nodes[i].squash = values.squash || this.nodes[i].squash; - } - }, - - /** - * Evolves the network to reach a lower error on a dataset - */ - evolve: async function (set, options) { - if (set[0].input.length !== this.input || set[0].output.length !== this.output) { - throw new Error('Dataset input/output size should be same as network input/output size!'); - } - - // Read the options - options = options || {}; - var targetError = typeof options.error !== 'undefined' ? options.error : 0.05; - var growth = typeof options.growth !== 'undefined' ? options.growth : 0.0001; - var cost = options.cost || methods.cost.MSE; - var amount = options.amount || 1; - - var threads = options.threads; - if (typeof threads === 'undefined') { - if (typeof window === 'undefined') { // Node.js - threads = __webpack_require__(25).cpus().length; - } else { // Browser - threads = navigator.hardwareConcurrency; - } - } - - var start = Date.now(); - - if (typeof options.iterations === 'undefined' && typeof options.error === 'undefined') { - throw new Error('At least one of the following options must be specified: error, iterations'); - } else if (typeof options.error === 'undefined') { - targetError = -1; // run until iterations - } else if (typeof options.iterations === 'undefined') { - options.iterations = 0; // run until target error - } - - var fitnessFunction; - if (threads === 1) { - // Create the fitness function - fitnessFunction = function (genome) { - var score = 0; - for (var i = 0; i < amount; i++) { - score -= genome.test(set, cost).error; - } - - score -= (genome.nodes.length - genome.input - genome.output + genome.connections.length + genome.gates.length) * growth; - score = isNaN(score) ? -Infinity : score; // this can cause problems with fitness proportionate selection - - return score / amount; - }; - } else { - // Serialize the dataset - var converted = multi.serializeDataSet(set); - - // Create workers, send datasets - var workers = []; - if (typeof window === 'undefined') { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.node.TestWorker(converted, cost)); - } - } else { - for (var i = 0; i < threads; i++) { - workers.push(new multi.workers.browser.TestWorker(converted, cost)); - } - } - - fitnessFunction = function (population) { - return new Promise((resolve, reject) => { - // Create a queue - var queue = population.slice(); - var done = 0; - - // Start worker function - var startWorker = function (worker) { - if (!queue.length) { - if (++done === threads) resolve(); - return; - } - - var genome = queue.shift(); - - worker.evaluate(genome).then(function (result) { - genome.score = -result; - genome.score -= (genome.nodes.length - genome.input - genome.output + - genome.connections.length + genome.gates.length) * growth; - genome.score = isNaN(parseFloat(result)) ? -Infinity : genome.score; - startWorker(worker); - }); - }; - - for (var i = 0; i < workers.length; i++) { - startWorker(workers[i]); - } - }); - }; - - options.fitnessPopulation = true; - } - - // Intialise the NEAT instance - options.network = this; - var neat = new Neat(this.input, this.output, fitnessFunction, options); - - var error = -Infinity; - var bestFitness = -Infinity; - var bestGenome; - - while (error < -targetError && (options.iterations === 0 || neat.generation < options.iterations)) { - let fittest = await neat.evolve(); - let fitness = fittest.score; - error = fitness + (fittest.nodes.length - fittest.input - fittest.output + fittest.connections.length + fittest.gates.length) * growth; - - if (fitness > bestFitness) { - bestFitness = fitness; - bestGenome = fittest; - } - - if (options.log && neat.generation % options.log === 0) { - console.log('iteration', neat.generation, 'fitness', fitness, 'error', -error); - } - - if (options.schedule && neat.generation % options.schedule.iterations === 0) { - options.schedule.function({ fitness: fitness, error: -error, iteration: neat.generation }); - } - } - - if (threads > 1) { - for (var i = 0; i < workers.length; i++) workers[i].terminate(); - } - - if (typeof bestGenome !== 'undefined') { - this.nodes = bestGenome.nodes; - this.connections = bestGenome.connections; - this.selfconns = bestGenome.selfconns; - this.gates = bestGenome.gates; - - if (options.clear) this.clear(); - } - - return { - error: -error, - iterations: neat.generation, - time: Date.now() - start - }; - }, - - /** - * Creates a standalone function of the network which can be run without the - * need of a library - */ - standalone: function () { - var present = []; - var activations = []; - var states = []; - var lines = []; - var functions = []; - - var i; - for (i = 0; i < this.input; i++) { - var node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - } - - lines.push('for(var i = 0; i < input.length; i++) A[i] = input[i];'); - - // So we don't have to use expensive .indexOf() - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].index = i; - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - activations.push(node.activation); - states.push(node.state); - - var functionIndex = present.indexOf(node.squash.name); - - if (functionIndex === -1) { - functionIndex = present.length; - present.push(node.squash.name); - functions.push(node.squash.toString()); - } - - var incoming = []; - for (var j = 0; j < node.connections.in.length; j++) { - var conn = node.connections.in[j]; - var computation = `A[${conn.from.index}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - if (node.connections.self.weight) { - let conn = node.connections.self; - let computation = `S[${i}] * ${conn.weight}`; - - if (conn.gater != null) { - computation += ` * A[${conn.gater.index}]`; - } - - incoming.push(computation); - } - - var line1 = `S[${i}] = ${incoming.join(' + ')} + ${node.bias};`; - var line2 = `A[${i}] = F[${functionIndex}](S[${i}])${!node.mask ? ' * ' + node.mask : ''};`; - lines.push(line1); - lines.push(line2); - } - - var output = []; - for (i = this.nodes.length - this.output; i < this.nodes.length; i++) { - output.push(`A[${i}]`); - } - - output = `return [${output.join(',')}];`; - lines.push(output); - - var total = ''; - total += `var F = [${functions.toString()}];\r\n`; - total += `var A = [${activations.toString()}];\r\n`; - total += `var S = [${states.toString()}];\r\n`; - total += `function activate(input){\r\n${lines.join('\r\n')}\r\n}`; - - return total; - }, - - /** - * Serialize to send to workers efficiently - */ - serialize: function () { - var activations = []; - var states = []; - var conns = []; - var squashes = [ - 'LOGISTIC', 'TANH', 'IDENTITY', 'STEP', 'RELU', 'SOFTSIGN', 'SINUSOID', - 'GAUSSIAN', 'BENT_IDENTITY', 'BIPOLAR', 'BIPOLAR_SIGMOID', 'HARD_TANH', - 'ABSOLUTE', 'INVERSE', 'SELU' - ]; - - conns.push(this.input); - conns.push(this.output); - - var i; - for (i = 0; i < this.nodes.length; i++) { - let node = this.nodes[i]; - node.index = i; - activations.push(node.activation); - states.push(node.state); - } - - for (i = this.input; i < this.nodes.length; i++) { - let node = this.nodes[i]; - conns.push(node.index); - conns.push(node.bias); - conns.push(squashes.indexOf(node.squash.name)); - - conns.push(node.connections.self.weight); - conns.push(node.connections.self.gater == null ? -1 : node.connections.self.gater.index); - - for (var j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - - conns.push(conn.from.index); - conns.push(conn.weight); - conns.push(conn.gater == null ? -1 : conn.gater.index); - } - - conns.push(-2); // stop token -> next node - } - - return [activations, states, conns]; - } -}; - -/** - * Convert a json object to a network - */ -Network.fromJSON = function (json) { - var network = new Network(json.input, json.output); - network.dropout = json.dropout; - network.nodes = []; - network.connections = []; - - var i; - for (i = 0; i < json.nodes.length; i++) { - network.nodes.push(Node.fromJSON(json.nodes[i])); - } - - for (i = 0; i < json.connections.length; i++) { - var conn = json.connections[i]; - - var connection = network.connect(network.nodes[conn.from], network.nodes[conn.to])[0]; - connection.weight = conn.weight; - - if (conn.gater != null) { - network.gate(network.nodes[conn.gater], connection); - } - } - - return network; -}; - -/** - * Merge two networks into one - */ -Network.merge = function (network1, network2) { - // Create a copy of the networks - network1 = Network.fromJSON(network1.toJSON()); - network2 = Network.fromJSON(network2.toJSON()); - - // Check if output and input size are the same - if (network1.output !== network2.input) { - throw new Error('Output size of network1 should be the same as the input size of network2!'); - } - - // Redirect all connections from network2 input from network1 output - var i; - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - if (conn.from.type === 'input') { - let index = network2.nodes.indexOf(conn.from); - - // redirect - conn.from = network1.nodes[network1.nodes.length - 1 - index]; - } - } - - // Delete input nodes of network2 - for (i = network2.input - 1; i >= 0; i--) { - network2.nodes.splice(i, 1); - } - - // Change the node type of network1's output nodes (now hidden) - for (i = network1.nodes.length - network1.output; i < network1.nodes.length; i++) { - network1.nodes[i].type = 'hidden'; - } - - // Create one network from both networks - network1.connections = network1.connections.concat(network2.connections); - network1.nodes = network1.nodes.concat(network2.nodes); - - return network1; -}; - -/** - * Create an offspring from two parent networks - */ -Network.crossOver = function (network1, network2, equal) { - if (network1.input !== network2.input || network1.output !== network2.output) { - throw new Error("Networks don't have the same input/output size!"); - } - - // Initialise offspring - var offspring = new Network(network1.input, network1.output); - offspring.connections = []; - offspring.nodes = []; - - // Save scores and create a copy - var score1 = network1.score || 0; - var score2 = network2.score || 0; - - // Determine offspring node size - var size; - if (equal || score1 === score2) { - let max = Math.max(network1.nodes.length, network2.nodes.length); - let min = Math.min(network1.nodes.length, network2.nodes.length); - size = Math.floor(Math.random() * (max - min + 1) + min); - } else if (score1 > score2) { - size = network1.nodes.length; - } else { - size = network2.nodes.length; - } - - // Rename some variables for easier reading - var outputSize = network1.output; - - // Set indexes so we don't need indexOf - var i; - for (i = 0; i < network1.nodes.length; i++) { - network1.nodes[i].index = i; - } - - for (i = 0; i < network2.nodes.length; i++) { - network2.nodes[i].index = i; - } - - // Assign nodes from parents to offspring - for (i = 0; i < size; i++) { - // Determine if an output node is needed - var node; - if (i < size - outputSize) { - let random = Math.random(); - node = random >= 0.5 ? network1.nodes[i] : network2.nodes[i]; - let other = random < 0.5 ? network1.nodes[i] : network2.nodes[i]; - - if (typeof node === 'undefined' || node.type === 'output') { - node = other; - } - } else { - if (Math.random() >= 0.5) { - node = network1.nodes[network1.nodes.length + i - size]; - } else { - node = network2.nodes[network2.nodes.length + i - size]; - } - } - - var newNode = new Node(); - newNode.bias = node.bias; - newNode.squash = node.squash; - newNode.type = node.type; - - offspring.nodes.push(newNode); - } - - // Create arrays of connection genes - var n1conns = {}; - var n2conns = {}; - - // Normal connections - for (i = 0; i < network1.connections.length; i++) { - let conn = network1.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network1.selfconns.length; i++) { - let conn = network1.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n1conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Normal connections - for (i = 0; i < network2.connections.length; i++) { - let conn = network2.connections[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Selfconnections - for (i = 0; i < network2.selfconns.length; i++) { - let conn = network2.selfconns[i]; - let data = { - weight: conn.weight, - from: conn.from.index, - to: conn.to.index, - gater: conn.gater != null ? conn.gater.index : -1 - }; - n2conns[Connection.innovationID(data.from, data.to)] = data; - } - - // Split common conn genes from disjoint or excess conn genes - var connections = []; - var keys1 = Object.keys(n1conns); - var keys2 = Object.keys(n2conns); - for (i = keys1.length - 1; i >= 0; i--) { - // Common gene - if (typeof n2conns[keys1[i]] !== 'undefined') { - let conn = Math.random() >= 0.5 ? n1conns[keys1[i]] : n2conns[keys1[i]]; - connections.push(conn); - - // Because deleting is expensive, just set it to some value - n2conns[keys1[i]] = undefined; - } else if (score1 >= score2 || equal) { - connections.push(n1conns[keys1[i]]); - } - } - - // Excess/disjoint gene - if (score2 >= score1 || equal) { - for (i = 0; i < keys2.length; i++) { - if (typeof n2conns[keys2[i]] !== 'undefined') { - connections.push(n2conns[keys2[i]]); - } - } - } - - // Add common conn genes uniformly - for (i = 0; i < connections.length; i++) { - let connData = connections[i]; - if (connData.to < size && connData.from < size) { - let from = offspring.nodes[connData.from]; - let to = offspring.nodes[connData.to]; - let conn = offspring.connect(from, to)[0]; - - conn.weight = connData.weight; - - if (connData.gater !== -1 && connData.gater < size) { - offspring.gate(offspring.nodes[connData.gater], conn); - } - } - } - - return offspring; -}; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - MULTITHREADING -*******************************************************************************/ - -var multi = { - /** Workers */ - workers: __webpack_require__(19), - - /** Serializes a dataset */ - serializeDataSet: function (dataSet) { - var serialized = [dataSet[0].input.length, dataSet[0].output.length]; - - for (var i = 0; i < dataSet.length; i++) { - var j; - for (j = 0; j < serialized[0]; j++) { - serialized.push(dataSet[i].input[j]); - } - for (j = 0; j < serialized[1]; j++) { - serialized.push(dataSet[i].output[j]); - } - } - - return serialized; - }, - - /** Activate a serialized network */ - activateSerializedNetwork: function (input, A, S, data, F) { - for (var i = 0; i < data[0]; i++) A[i] = input[i]; - for (i = 2; i < data.length; i++) { - let index = data[i++]; - let bias = data[i++]; - let squash = data[i++]; - let selfweight = data[i++]; - let selfgater = data[i++]; - - S[index] = (selfgater === -1 ? 1 : A[selfgater]) * selfweight * S[index] + bias; - - while (data[i] !== -2) { - S[index] += A[data[i++]] * data[i++] * (data[i++] === -1 ? 1 : A[data[i - 1]]); - } - A[index] = F[squash](S[index]); - } - - var output = []; - for (i = A.length - data[1]; i < A.length; i++) output.push(A[i]); - return output; - }, - - /** Deserializes a dataset to an array of arrays */ - deserializeDataSet: function (serializedSet) { - var set = []; - - var sampleSize = serializedSet[0] + serializedSet[1]; - for (var i = 0; i < (serializedSet.length - 2) / sampleSize; i++) { - let input = []; - for (var j = 2 + i * sampleSize; j < 2 + i * sampleSize + serializedSet[0]; j++) { - input.push(serializedSet[j]); - } - let output = []; - for (j = 2 + i * sampleSize + serializedSet[0]; j < 2 + i * sampleSize + sampleSize; j++) { - output.push(serializedSet[j]); - } - set.push(input); - set.push(output); - } - - return set; - }, - - /** A list of compiled activation functions in a certain order */ - activations: [ - function (x) { return 1 / (1 + Math.exp(-x)); }, - function (x) { return Math.tanh(x); }, - function (x) { return x; }, - function (x) { return x > 0 ? 1 : 0; }, - function (x) { return x > 0 ? x : 0; }, - function (x) { return x / (1 + Math.abs(x)); }, - function (x) { return Math.sin(x); }, - function (x) { return Math.exp(-Math.pow(x, 2)); }, - function (x) { return (Math.sqrt(Math.pow(x, 2) + 1) - 1) / 2 + x; }, - function (x) { return x > 0 ? 1 : -1; }, - function (x) { return 2 / (1 + Math.exp(-x)) - 1; }, - function (x) { return Math.max(-1, Math.min(1, x)); }, - function (x) { return Math.abs(x); }, - function (x) { return 1 - x; }, - function (x) { - var a = 1.6732632423543772848170429916717; - return (x > 0 ? x : a * Math.exp(x) - a) * 1.0507009873554804934193349852946; - } - ] -}; - -multi.testSerializedSet = function (set, cost, A, S, data, F) { - // Calculate how much samples are in the set - var error = 0; - for (var i = 0; i < set.length; i += 2) { - let output = multi.activateSerializedNetwork(set[i], A, S, data, F); - error += cost(set[i + 1], output); - } - - return error / (set.length / 2); -}; - -/* Export */ -for (var i in multi) { - module.exports[i] = multi[i]; -} - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Group; - -/* Import */ -var methods = __webpack_require__(0); -var config = __webpack_require__(1); -var Layer = __webpack_require__(7); -var Node = __webpack_require__(2); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Group (size) { - this.nodes = []; - this.connections = { - in: [], - out: [], - self: [] - }; - - for (var i = 0; i < size; i++) { - this.nodes.push(new Node()); - } -} - -Group.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum, true); - } else { - this.nodes[i].propagate(rate, momentum, true, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections = []; - var i, j; - if (target instanceof Group) { - if (typeof method === 'undefined') { - if (this !== target) { - if (config.warnings) console.warn('No group connection specified, using ALL_TO_ALL'); - method = methods.connection.ALL_TO_ALL; - } else { - if (config.warnings) console.warn('No group connection specified, using ONE_TO_ONE'); - method = methods.connection.ONE_TO_ONE; - } - } - if (method === methods.connection.ALL_TO_ALL || method === methods.connection.ALL_TO_ELSE) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - if (method === methods.connection.ALL_TO_ELSE && this.nodes[i] === target.nodes[j]) continue; - let connection = this.nodes[i].connect(target.nodes[j], weight); - this.connections.out.push(connection[0]); - target.connections.in.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (method === methods.connection.ONE_TO_ONE) { - if (this.nodes.length !== target.nodes.length) { - throw new Error('From and To group must be the same size!'); - } - - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target.nodes[i], weight); - this.connections.self.push(connection[0]); - connections.push(connection[0]); - } - } - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - let connection = this.nodes[i].connect(target, weight); - this.connections.out.push(connection[0]); - connections.push(connection[0]); - } - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - if (typeof method === 'undefined') { - throw new Error('Please specify Gating.INPUT, Gating.OUTPUT'); - } - - if (!Array.isArray(connections)) { - connections = [connections]; - } - - var nodes1 = []; - var nodes2 = []; - - var i, j; - for (i = 0; i < connections.length; i++) { - var connection = connections[i]; - if (!nodes1.includes(connection.from)) nodes1.push(connection.from); - if (!nodes2.includes(connection.to)) nodes2.push(connection.to); - } - - switch (method) { - case methods.gating.INPUT: - for (i = 0; i < nodes2.length; i++) { - let node = nodes2[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.in.length; j++) { - let conn = node.connections.in[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.OUTPUT: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - for (j = 0; j < node.connections.out.length; j++) { - let conn = node.connections.out[j]; - if (connections.includes(conn)) { - gater.gate(conn); - } - } - } - break; - case methods.gating.SELF: - for (i = 0; i < nodes1.length; i++) { - let node = nodes1[i]; - let gater = this.nodes[i % this.nodes.length]; - - if (connections.includes(node.connections.self)) { - gater.gate(node.connections.self); - } - } - } - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - if (typeof values.bias !== 'undefined') { - this.nodes[i].bias = values.bias; - } - - this.nodes[i].squash = values.squash || this.nodes[i].squash; - this.nodes[i].type = values.type || this.nodes[i].type; - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (j = this.connections.in.length - 1; j >= 0; j--) { - var conn = this.connections.in[j]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(j, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Layer; - -/* Import */ -var methods = __webpack_require__(0); -var Group = __webpack_require__(6); -var Node = __webpack_require__(2); - -/******************************************************************************* - Group -*******************************************************************************/ - -function Layer () { - this.output = null; - - this.nodes = []; - this.connections = { in: [], - out: [], - self: [] - }; -} - -Layer.prototype = { - /** - * Activates all the nodes in the group - */ - activate: function (value) { - var values = []; - - if (typeof value !== 'undefined' && value.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = 0; i < this.nodes.length; i++) { - var activation; - if (typeof value === 'undefined') { - activation = this.nodes[i].activate(); - } else { - activation = this.nodes[i].activate(value[i]); - } - - values.push(activation); - } - - return values; - }, - - /** - * Propagates all the node in the group - */ - propagate: function (rate, momentum, target) { - if (typeof target !== 'undefined' && target.length !== this.nodes.length) { - throw new Error('Array with values should be same as the amount of nodes!'); - } - - for (var i = this.nodes.length - 1; i >= 0; i--) { - if (typeof target === 'undefined') { - this.nodes[i].propagate(rate, momentum, true); - } else { - this.nodes[i].propagate(rate, momentum, true, target[i]); - } - } - }, - - /** - * Connects the nodes in this group to nodes in another group or just a node - */ - connect: function (target, method, weight) { - var connections; - if (target instanceof Group || target instanceof Node) { - connections = this.output.connect(target, method, weight); - } else if (target instanceof Layer) { - connections = target.input(this, method, weight); - } - - return connections; - }, - - /** - * Make nodes from this group gate the given connection(s) - */ - gate: function (connections, method) { - this.output.gate(connections, method); - }, - - /** - * Sets the value of a property for every node - */ - set: function (values) { - for (var i = 0; i < this.nodes.length; i++) { - var node = this.nodes[i]; - - if (node instanceof Node) { - if (typeof values.bias !== 'undefined') { - node.bias = values.bias; - } - - node.squash = values.squash || node.squash; - node.type = values.type || node.type; - } else if (node instanceof Group) { - node.set(values); - } - } - }, - - /** - * Disconnects all nodes from this group from another given group/node - */ - disconnect: function (target, twosided) { - twosided = twosided || false; - - // In the future, disconnect will return a connection so indexOf can be used - var i, j, k; - if (target instanceof Group) { - for (i = 0; i < this.nodes.length; i++) { - for (j = 0; j < target.nodes.length; j++) { - this.nodes[i].disconnect(target.nodes[j], twosided); - - for (k = this.connections.out.length - 1; k >= 0; k--) { - let conn = this.connections.out[k]; - - if (conn.from === this.nodes[i] && conn.to === target.nodes[j]) { - this.connections.out.splice(k, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target.nodes[j] && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - } else if (target instanceof Node) { - for (i = 0; i < this.nodes.length; i++) { - this.nodes[i].disconnect(target, twosided); - - for (j = this.connections.out.length - 1; j >= 0; j--) { - let conn = this.connections.out[j]; - - if (conn.from === this.nodes[i] && conn.to === target) { - this.connections.out.splice(j, 1); - break; - } - } - - if (twosided) { - for (k = this.connections.in.length - 1; k >= 0; k--) { - let conn = this.connections.in[k]; - - if (conn.from === target && conn.to === this.nodes[i]) { - this.connections.in.splice(k, 1); - break; - } - } - } - } - } - }, - - /** - * Clear the context of this group - */ - clear: function () { - for (var i = 0; i < this.nodes.length; i++) { - this.nodes[i].clear(); - } - } -}; - -Layer.Dense = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var block = new Group(size); - - layer.nodes.push(block); - layer.output = block; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - return from.connect(block, method, weight); - }; - - return layer; -}; - -Layer.LSTM = function (size) { - // Create the layer - var layer = new Layer(); - - // Init required nodes (in activation order) - var inputGate = new Group(size); - var forgetGate = new Group(size); - var memoryCell = new Group(size); - var outputGate = new Group(size); - var outputBlock = new Group(size); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Add to nodes array - layer.nodes = [inputGate, forgetGate, memoryCell, outputGate, outputBlock]; - - // Define output - layer.output = outputBlock; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - var input = from.connect(memoryCell, method, weight); - connections = connections.concat(input); - - connections = connections.concat(from.connect(inputGate, method, weight)); - connections = connections.concat(from.connect(outputGate, method, weight)); - connections = connections.concat(from.connect(forgetGate, method, weight)); - - inputGate.gate(input, methods.gating.INPUT); - - return connections; - }; - - return layer; -}; - -Layer.GRU = function (size) { - // Create the layer - var layer = new Layer(); - - var updateGate = new Group(size); - var inverseUpdateGate = new Group(size); - var resetGate = new Group(size); - var memoryCell = new Group(size); - var output = new Group(size); - var previousOutput = new Group(size); - - previousOutput.set({ - bias: 0, - squash: methods.activation.IDENTITY, - type: 'constant' - }); - memoryCell.set({ - squash: methods.activation.TANH - }); - inverseUpdateGate.set({ - bias: 0, - squash: methods.activation.INVERSE, - type: 'constant' - }); - updateGate.set({ - bias: 1 - }); - resetGate.set({ - bias: 0 - }); - - // Update gate calculation - previousOutput.connect(updateGate, methods.connection.ALL_TO_ALL); - - // Inverse update gate calculation - updateGate.connect(inverseUpdateGate, methods.connection.ONE_TO_ONE, 1); - - // Reset gate calculation - previousOutput.connect(resetGate, methods.connection.ALL_TO_ALL); - - // Memory calculation - var reset = previousOutput.connect(memoryCell, methods.connection.ALL_TO_ALL); - - resetGate.gate(reset, methods.gating.OUTPUT); // gate - - // Output calculation - var update1 = previousOutput.connect(output, methods.connection.ALL_TO_ALL); - var update2 = memoryCell.connect(output, methods.connection.ALL_TO_ALL); - - updateGate.gate(update1, methods.gating.OUTPUT); - inverseUpdateGate.gate(update2, methods.gating.OUTPUT); - - // Previous output calculation - output.connect(previousOutput, methods.connection.ONE_TO_ONE, 1); - - // Add to nodes array - layer.nodes = [updateGate, inverseUpdateGate, resetGate, memoryCell, output, previousOutput]; - - layer.output = output; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - var connections = []; - - connections = connections.concat(from.connect(updateGate, method, weight)); - connections = connections.concat(from.connect(resetGate, method, weight)); - connections = connections.concat(from.connect(memoryCell, method, weight)); - - return connections; - }; - - return layer; -}; - -Layer.Memory = function (size, memory) { - // Create the layer - var layer = new Layer(); - // Because the output can only be one group, we have to put the nodes all in óne group - - var previous = null; - var i; - for (i = 0; i < memory; i++) { - var block = new Group(size); - - block.set({ - squash: methods.activation.IDENTITY, - bias: 0, - type: 'constant' - }); - - if (previous != null) { - previous.connect(block, methods.connection.ONE_TO_ONE, 1); - } - - layer.nodes.push(block); - previous = block; - } - - layer.nodes.reverse(); - - for (i = 0; i < layer.nodes.length; i++) { - layer.nodes[i].nodes.reverse(); - } - - // Because output can only be óne group, fit all memory nodes in óne group - var outputGroup = new Group(0); - for (var group in layer.nodes) { - outputGroup.nodes = outputGroup.nodes.concat(layer.nodes[group].nodes); - } - layer.output = outputGroup; - - layer.input = function (from, method, weight) { - if (from instanceof Layer) from = from.output; - method = method || methods.connection.ALL_TO_ALL; - - if (from.nodes.length !== layer.nodes[layer.nodes.length - 1].nodes.length) { - throw new Error('Previous layer size must be same as memory size'); - } - - return from.connect(layer.nodes[layer.nodes.length - 1], methods.connection.ONE_TO_ONE, 1); - }; - - return layer; -}; - - -/***/ }), -/* 8 */ -/***/ (function(module, exports) { - -/******************************************************************************* - ACTIVATION FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Activation_function -// https://stats.stackexchange.com/questions/115258/comprehensive-list-of-activation-functions-in-neural-networks-with-pros-cons -var activation = { - LOGISTIC: function (x, derivate) { - var fx = 1 / (1 + Math.exp(-x)); - if (!derivate) return fx; - return fx * (1 - fx); - }, - TANH: function (x, derivate) { - if (derivate) return 1 - Math.pow(Math.tanh(x), 2); - return Math.tanh(x); - }, - IDENTITY: function (x, derivate) { - return derivate ? 1 : x; - }, - STEP: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : 0; - }, - RELU: function (x, derivate) { - if (derivate) return x > 0 ? 1 : 0; - return x > 0 ? x : 0; - }, - SOFTSIGN: function (x, derivate) { - var d = 1 + Math.abs(x); - if (derivate) return x / Math.pow(d, 2); - return x / d; - }, - SINUSOID: function (x, derivate) { - if (derivate) return Math.cos(x); - return Math.sin(x); - }, - GAUSSIAN: function (x, derivate) { - var d = Math.exp(-Math.pow(x, 2)); - if (derivate) return -2 * x * d; - return d; - }, - BENT_IDENTITY: function (x, derivate) { - var d = Math.sqrt(Math.pow(x, 2) + 1); - if (derivate) return x / (2 * d) + 1; - return (d - 1) / 2 + x; - }, - BIPOLAR: function (x, derivate) { - return derivate ? 0 : x > 0 ? 1 : -1; - }, - BIPOLAR_SIGMOID: function (x, derivate) { - var d = 2 / (1 + Math.exp(-x)) - 1; - if (derivate) return 1 / 2 * (1 + d) * (1 - d); - return d; - }, - HARD_TANH: function (x, derivate) { - if (derivate) return x > -1 && x < 1 ? 1 : 0; - return Math.max(-1, Math.min(1, x)); - }, - ABSOLUTE: function (x, derivate) { - if (derivate) return x < 0 ? -1 : 1; - return Math.abs(x); - }, - INVERSE: function (x, derivate) { - if (derivate) return -1; - return 1 - x; - }, - // https://arxiv.org/pdf/1706.02515.pdf - SELU: function (x, derivate) { - var alpha = 1.6732632423543772848170429916717; - var scale = 1.0507009873554804934193349852946; - var fx = x > 0 ? x : alpha * Math.exp(x) - alpha; - if (derivate) { return x > 0 ? scale : (fx + alpha) * scale; } - return fx * scale; - } -}; - -/* Export */ -module.exports = activation; - - -/***/ }), -/* 9 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = Neat; - -/* Import */ -var Network = __webpack_require__(4); -var methods = __webpack_require__(0); -var config = __webpack_require__(1); - -/* Easier variable naming */ -var selection = methods.selection; - -/******************************************************************************* - NEAT -*******************************************************************************/ - -function Neat (input, output, fitness, options) { - this.input = input; // The input size of the networks - this.output = output; // The output size of the networks - this.fitness = fitness; // The fitness function to evaluate the networks - - // Configure options - options = options || {}; - this.equal = options.equal || false; - this.clear = options.clear || false; - this.popsize = options.popsize || 50; - this.elitism = options.elitism || 0; - this.provenance = options.provenance || 0; - this.mutationRate = options.mutationRate || 0.3; - this.mutationAmount = options.mutationAmount || 1; - - this.fitnessPopulation = options.fitnessPopulation || false; - - this.selection = options.selection || methods.selection.POWER; - this.crossover = options.crossover || [ - methods.crossover.SINGLE_POINT, - methods.crossover.TWO_POINT, - methods.crossover.UNIFORM, - methods.crossover.AVERAGE - ]; - this.mutation = options.mutation || methods.mutation.FFW; - - this.template = options.network || false; - - this.maxNodes = options.maxNodes || Infinity; - this.maxConns = options.maxConns || Infinity; - this.maxGates = options.maxGates || Infinity; - - // Custom mutation selection function if given - this.selectMutationMethod = typeof options.mutationSelection === 'function' ? options.mutationSelection.bind(this) : this.selectMutationMethod; - - // Generation counter - this.generation = 0; - - // Initialise the genomes - this.createPool(this.template); -} - -Neat.prototype = { - /** - * Create the initial pool of genomes - */ - createPool: function (network) { - this.population = []; - - for (var i = 0; i < this.popsize; i++) { - var copy; - if (this.template) { - copy = Network.fromJSON(network.toJSON()); - } else { - copy = new Network(this.input, this.output); - } - copy.score = undefined; - this.population.push(copy); - } - }, - - /** - * Evaluates, selects, breeds and mutates population - */ - evolve: async function () { - // Check if evaluated, sort the population - if (typeof this.population[this.population.length - 1].score === 'undefined') { - await this.evaluate(); - } - this.sort(); - - var fittest = Network.fromJSON(this.population[0].toJSON()); - fittest.score = this.population[0].score; - - var newPopulation = []; - - // Elitism - var elitists = []; - for (var i = 0; i < this.elitism; i++) { - elitists.push(this.population[i]); - } - - // Provenance - for (i = 0; i < this.provenance; i++) { - newPopulation.push(Network.fromJSON(this.template.toJSON())); - } - - // Breed the next individuals - for (i = 0; i < this.popsize - this.elitism - this.provenance; i++) { - newPopulation.push(this.getOffspring()); - } - - // Replace the old population with the new population - this.population = newPopulation; - this.mutate(); - - this.population.push(...elitists); - - // Reset the scores - for (i = 0; i < this.population.length; i++) { - this.population[i].score = undefined; - } - - this.generation++; - - return fittest; - }, - - /** - * Breeds two parents into an offspring, population MUST be surted - */ - getOffspring: function () { - var parent1 = this.getParent(); - var parent2 = this.getParent(); - - return Network.crossOver(parent1, parent2, this.equal); - }, - - /** - * Selects a random mutation method for a genome according to the parameters - */ - selectMutationMethod: function (genome) { - var mutationMethod = this.mutation[Math.floor(Math.random() * this.mutation.length)]; - - if (mutationMethod === methods.mutation.ADD_NODE && genome.nodes.length >= this.maxNodes) { - if (config.warnings) console.warn('maxNodes exceeded!'); - return; - } - - if (mutationMethod === methods.mutation.ADD_CONN && genome.connections.length >= this.maxConns) { - if (config.warnings) console.warn('maxConns exceeded!'); - return; - } - - if (mutationMethod === methods.mutation.ADD_GATE && genome.gates.length >= this.maxGates) { - if (config.warnings) console.warn('maxGates exceeded!'); - return; - } - - return mutationMethod; - }, - - /** - * Mutates the given (or current) population - */ - mutate: function () { - // Elitist genomes should not be included - for (var i = 0; i < this.population.length; i++) { - if (Math.random() <= this.mutationRate) { - for (var j = 0; j < this.mutationAmount; j++) { - var mutationMethod = this.selectMutationMethod(this.population[i]); - this.population[i].mutate(mutationMethod); - } - } - } - }, - - /** - * Evaluates the current population - */ - evaluate: async function () { - var i; - if (this.fitnessPopulation) { - if (this.clear) { - for (i = 0; i < this.population.length; i++) { - this.population[i].clear(); - } - } - await this.fitness(this.population); - } else { - for (i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - if (this.clear) genome.clear(); - genome.score = await this.fitness(genome); - } - } - }, - - /** - * Sorts the population by score - */ - sort: function () { - this.population.sort(function (a, b) { - return b.score - a.score; - }); - }, - - /** - * Returns the fittest genome of the current population - */ - getFittest: function () { - // Check if evaluated - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - if (this.population[0].score < this.population[1].score) { - this.sort(); - } - - return this.population[0]; - }, - - /** - * Returns the average fitness of the current population - */ - getAverage: function () { - if (typeof this.population[this.population.length - 1].score === 'undefined') { - this.evaluate(); - } - - var score = 0; - for (var i = 0; i < this.population.length; i++) { - score += this.population[i].score; - } - - return score / this.population.length; - }, - - /** - * Gets a genome based on the selection function - * @return {Network} genome - */ - getParent: function () { - var i; - switch (this.selection) { - case selection.POWER: - if (this.population[0].score < this.population[1].score) this.sort(); - - var index = Math.floor(Math.pow(Math.random(), this.selection.power) * this.population.length); - return this.population[index]; - case selection.FITNESS_PROPORTIONATE: - // As negative fitnesses are possible - // https://stackoverflow.com/questions/16186686/genetic-algorithm-handling-negative-fitness-values - // this is unnecessarily run for every individual, should be changed - - var totalFitness = 0; - var minimalFitness = 0; - for (i = 0; i < this.population.length; i++) { - var score = this.population[i].score; - minimalFitness = score < minimalFitness ? score : minimalFitness; - totalFitness += score; - } - - minimalFitness = Math.abs(minimalFitness); - totalFitness += minimalFitness * this.population.length; - - var random = Math.random() * totalFitness; - var value = 0; - - for (i = 0; i < this.population.length; i++) { - let genome = this.population[i]; - value += genome.score + minimalFitness; - if (random < value) return genome; - } - - // if all scores equal, return random genome - return this.population[Math.floor(Math.random() * this.population.length)]; - case selection.TOURNAMENT: - if (this.selection.size > this.popsize) { - throw new Error('Your tournament size should be lower than the population size, please change methods.selection.TOURNAMENT.size'); - } - - // Create a tournament - var individuals = []; - for (i = 0; i < this.selection.size; i++) { - let random = this.population[Math.floor(Math.random() * this.population.length)]; - individuals.push(random); - } - - // Sort the tournament individuals by score - individuals.sort(function (a, b) { - return b.score - a.score; - }); - - // Select an individual - for (i = 0; i < this.selection.size; i++) { - if (Math.random() < this.selection.probability || i === this.selection.size - 1) { - return individuals[i]; - } - } - } - }, - - /** - * Export the current population to a json object - */ - export: function () { - var json = []; - for (var i = 0; i < this.population.length; i++) { - var genome = this.population[i]; - json.push(genome.toJSON()); - } - - return json; - }, - - /** - * Import population from a json object - */ - import: function (json) { - var population = []; - for (var i = 0; i < json.length; i++) { - var genome = json[i]; - population.push(Network.fromJSON(genome)); - } - this.population = population; - this.popsize = population.length; - } -}; - - -/***/ }), -/* 10 */ -/***/ (function(module, exports, __webpack_require__) { - -var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;var Neataptic = { - methods: __webpack_require__(0), - Connection: __webpack_require__(3), - architect: __webpack_require__(18), - Network: __webpack_require__(4), - config: __webpack_require__(1), - Group: __webpack_require__(6), - Layer: __webpack_require__(7), - Node: __webpack_require__(2), - Neat: __webpack_require__(9), - multi: __webpack_require__(5) -}; - -// CommonJS & AMD -if (true) { - !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = function () { return Neataptic; }.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); -} - -// Node.js -if (typeof module !== 'undefined' && module.exports) { - module.exports = Neataptic; -} - -// Browser -if (typeof window === 'object') { - (function () { - var old = window['neataptic']; - Neataptic.ninja = function () { - window['neataptic'] = old; - return Neataptic; - }; - })(); - - window['neataptic'] = Neataptic; -} - - -/***/ }), -/* 11 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var activation = __webpack_require__(8); - -/******************************************************************************* - MUTATION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/mutation_(genetic_algorithm) -var mutation = { - ADD_NODE: { - name: 'ADD_NODE' - }, - SUB_NODE: { - name: 'SUB_NODE', - keep_gates: true - }, - ADD_CONN: { - name: 'ADD_CONN' - }, - SUB_CONN: { - name: 'REMOVE_CONN' - }, - MOD_WEIGHT: { - name: 'MOD_WEIGHT', - min: -1, - max: 1 - }, - MOD_BIAS: { - name: 'MOD_BIAS', - min: -1, - max: 1 - }, - MOD_ACTIVATION: { - name: 'MOD_ACTIVATION', - mutateOutput: true, - allowed: [ - activation.LOGISTIC, - activation.TANH, - activation.RELU, - activation.IDENTITY, - activation.STEP, - activation.SOFTSIGN, - activation.SINUSOID, - activation.GAUSSIAN, - activation.BENT_IDENTITY, - activation.BIPOLAR, - activation.BIPOLAR_SIGMOID, - activation.HARD_TANH, - activation.ABSOLUTE, - activation.INVERSE, - activation.SELU - ] - }, - ADD_SELF_CONN: { - name: 'ADD_SELF_CONN' - }, - SUB_SELF_CONN: { - name: 'SUB_SELF_CONN' - }, - ADD_GATE: { - name: 'ADD_GATE' - }, - SUB_GATE: { - name: 'SUB_GATE' - }, - ADD_BACK_CONN: { - name: 'ADD_BACK_CONN' - }, - SUB_BACK_CONN: { - name: 'SUB_BACK_CONN' - }, - SWAP_NODES: { - name: 'SWAP_NODES', - mutateOutput: true - } -}; - -mutation.ALL = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.ADD_GATE, - mutation.SUB_GATE, - mutation.ADD_SELF_CONN, - mutation.SUB_SELF_CONN, - mutation.ADD_BACK_CONN, - mutation.SUB_BACK_CONN, - mutation.SWAP_NODES -]; - -mutation.FFW = [ - mutation.ADD_NODE, - mutation.SUB_NODE, - mutation.ADD_CONN, - mutation.SUB_CONN, - mutation.MOD_WEIGHT, - mutation.MOD_BIAS, - mutation.MOD_ACTIVATION, - mutation.SWAP_NODES -]; - -/* Export */ -module.exports = mutation; - - -/***/ }), -/* 12 */ -/***/ (function(module, exports) { - -/******************************************************************************* - SELECTION -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Selection_(genetic_algorithm) - -var selection = { - FITNESS_PROPORTIONATE: { - name: 'FITNESS_PROPORTIONATE' - }, - POWER: { - name: 'POWER', - power: 4 - }, - TOURNAMENT: { - name: 'TOURNAMENT', - size: 5, - probability: 0.5 - } -}; - -/* Export */ -module.exports = selection; - - -/***/ }), -/* 13 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CROSSOVER -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Crossover_(genetic_algorithm) -var crossover = { - SINGLE_POINT: { - name: 'SINGLE_POINT', - config: [0.4] - }, - TWO_POINT: { - name: 'TWO_POINT', - config: [0.4, 0.9] - }, - UNIFORM: { - name: 'UNIFORM' - }, - AVERAGE: { - name: 'AVERAGE' - } -}; - -/* Export */ -module.exports = crossover; - - -/***/ }), -/* 14 */ -/***/ (function(module, exports) { - -/******************************************************************************* - COST FUNCTIONS -*******************************************************************************/ - -// https://en.wikipedia.org/wiki/Loss_function -var cost = { - // Cross entropy error - CROSS_ENTROPY: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - // Avoid negative and zero numbers, use 1e-15 http://bit.ly/2p5W29A - error -= target[i] * Math.log(Math.max(output[i], 1e-15)) + (1 - target[i]) * Math.log(1 - Math.max(output[i], 1e-15)); - } - return error / output.length; - }, - // Mean Squared Error - MSE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.pow(target[i] - output[i], 2); - } - - return error / output.length; - }, - // Binary error - BINARY: function (target, output) { - var misses = 0; - for (var i = 0; i < output.length; i++) { - misses += Math.round(target[i] * 2) !== Math.round(output[i] * 2); - } - - return misses; - }, - // Mean Absolute Error - MAE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs(target[i] - output[i]); - } - - return error / output.length; - }, - // Mean Absolute Percentage Error - MAPE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.abs((output[i] - target[i]) / Math.max(target[i], 1e-15)); - } - - return error / output.length; - }, - // Mean Squared Logarithmic Error - MSLE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.log(Math.max(target[i], 1e-15)) - Math.log(Math.max(output[i], 1e-15)); - } - - return error; - }, - // Hinge loss, for classifiers - HINGE: function (target, output) { - var error = 0; - for (var i = 0; i < output.length; i++) { - error += Math.max(0, 1 - target[i] * output[i]); - } - - return error; - } -}; - -/* Export */ -module.exports = cost; - - -/***/ }), -/* 15 */ -/***/ (function(module, exports) { - -/******************************************************************************* - GATING -*******************************************************************************/ - -// Specifies how to gate a connection between two groups of multiple neurons -var gating = { - OUTPUT: { - name: 'OUTPUT' - }, - INPUT: { - name: 'INPUT' - }, - SELF: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = gating; - - -/***/ }), -/* 16 */ -/***/ (function(module, exports) { - -/******************************************************************************* - CONNECTION -*******************************************************************************/ - -// Specifies in what manner two groups are connected -var connection = { - ALL_TO_ALL: { - name: 'OUTPUT' - }, - ALL_TO_ELSE: { - name: 'INPUT' - }, - ONE_TO_ONE: { - name: 'SELF' - } -}; - -/* Export */ -module.exports = connection; - - -/***/ }), -/* 17 */ -/***/ (function(module, exports) { - -/******************************************************************************* - RATE -*******************************************************************************/ - -// https://stackoverflow.com/questions/30033096/what-is-lr-policy-in-caffe/30045244 -var rate = { - FIXED: function () { - var func = function (baseRate, iteration) { return baseRate; }; - return func; - }, - STEP: function (gamma, stepSize) { - gamma = gamma || 0.9; - stepSize = stepSize || 100; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, Math.floor(iteration / stepSize)); - }; - - return func; - }, - EXP: function (gamma) { - gamma = gamma || 0.999; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(gamma, iteration); - }; - - return func; - }, - INV: function (gamma, power) { - gamma = gamma || 0.001; - power = power || 2; - - var func = function (baseRate, iteration) { - return baseRate * Math.pow(1 + gamma * iteration, -power); - }; - - return func; - } -}; - -/* Export */ -module.exports = rate; - - -/***/ }), -/* 18 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Import */ -var methods = __webpack_require__(0); -var Network = __webpack_require__(4); -var Group = __webpack_require__(6); -var Layer = __webpack_require__(7); -var Node = __webpack_require__(2); - -/******************************************************************************* - architect -*******************************************************************************/ - -var architect = { - /** - * Constructs a network from a given array of connected nodes - */ - Construct: function (list) { - // Create a network - var network = new Network(0, 0); - - // Transform all groups into nodes - var nodes = []; - - var i; - for (i = 0; i < list.length; i++) { - let j; - if (list[i] instanceof Group) { - for (j = 0; j < list[i].nodes.length; j++) { - nodes.push(list[i].nodes[j]); - } - } else if (list[i] instanceof Layer) { - for (j = 0; j < list[i].nodes.length; j++) { - for (var k = 0; k < list[i].nodes[j].nodes.length; k++) { - nodes.push(list[i].nodes[j].nodes[k]); - } - } - } else if (list[i] instanceof Node) { - nodes.push(list[i]); - } - } - - // Determine input and output nodes - var inputs = []; - var outputs = []; - for (i = nodes.length - 1; i >= 0; i--) { - if (nodes[i].type === 'output' || nodes[i].connections.out.length + nodes[i].connections.gated.length === 0) { - nodes[i].type = 'output'; - network.output++; - outputs.push(nodes[i]); - nodes.splice(i, 1); - } else if (nodes[i].type === 'input' || !nodes[i].connections.in.length) { - nodes[i].type = 'input'; - network.input++; - inputs.push(nodes[i]); - nodes.splice(i, 1); - } - } - - // Input nodes are always first, output nodes are always last - nodes = inputs.concat(nodes).concat(outputs); - - if (network.input === 0 || network.output === 0) { - throw new Error('Given nodes have no clear input/output node!'); - } - - for (i = 0; i < nodes.length; i++) { - let j; - for (j = 0; j < nodes[i].connections.out.length; j++) { - network.connections.push(nodes[i].connections.out[j]); - } - for (j = 0; j < nodes[i].connections.gated.length; j++) { - network.gates.push(nodes[i].connections.gated[j]); - } - if (nodes[i].connections.self.weight !== 0) { - network.selfconns.push(nodes[i].connections.self); - } - } - - network.nodes = nodes; - - return network; - }, - - /** - * Creates a multilayer perceptron (MLP) - */ - Perceptron: function () { - // Convert arguments to Array - var layers = Array.prototype.slice.call(arguments); - if (layers.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - // Create a list of nodes/groups - var nodes = []; - nodes.push(new Group(layers[0])); - - for (var i = 1; i < layers.length; i++) { - var layer = layers[i]; - layer = new Group(layer); - nodes.push(layer); - nodes[i - 1].connect(nodes[i], methods.connection.ALL_TO_ALL); - } - - // Construct the network - return architect.Construct(nodes); - }, - - /** - * Creates a randomly connected network - */ - Random: function (input, hidden, output, options) { - options = options || {}; - - var connections = options.connections || hidden * 2; - var backconnections = options.backconnections || 0; - var selfconnections = options.selfconnections || 0; - var gates = options.gates || 0; - - var network = new Network(input, output); - - var i; - for (i = 0; i < hidden; i++) { - network.mutate(methods.mutation.ADD_NODE); - } - - for (i = 0; i < connections - hidden; i++) { - network.mutate(methods.mutation.ADD_CONN); - } - - for (i = 0; i < backconnections; i++) { - network.mutate(methods.mutation.ADD_BACK_CONN); - } - - for (i = 0; i < selfconnections; i++) { - network.mutate(methods.mutation.ADD_SELF_CONN); - } - - for (i = 0; i < gates; i++) { - network.mutate(methods.mutation.ADD_GATE); - } - - return network; - }, - - /** - * Creates a long short-term memory network - */ - LSTM: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('You have to specify at least 3 layers'); - } - - var last = args.pop(); - - var outputLayer; - if (typeof last === 'number') { - outputLayer = new Group(last); - last = {}; - } else { - outputLayer = new Group(args.pop()); // last argument - } - - outputLayer.set({ - type: 'output' - }); - - var options = {}; - options.memoryToMemory = last.memoryToMemory || false; - options.outputToMemory = last.outputToMemory || false; - options.outputToGates = last.outputToGates || false; - options.inputToOutput = last.inputToOutput === undefined ? true : last.inputToOutput; - options.inputToDeep = last.inputToDeep === undefined ? true : last.inputToDeep; - - var inputLayer = new Group(args.shift()); // first argument - inputLayer.set({ - type: 'input' - }); - - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var block = blocks[i]; - - // Init required nodes (in activation order) - var inputGate = new Group(block); - var forgetGate = new Group(block); - var memoryCell = new Group(block); - var outputGate = new Group(block); - var outputBlock = i === blocks.length - 1 ? outputLayer : new Group(block); - - inputGate.set({ - bias: 1 - }); - forgetGate.set({ - bias: 1 - }); - outputGate.set({ - bias: 1 - }); - - // Connect the input with all the nodes - var input = previous.connect(memoryCell, methods.connection.ALL_TO_ALL); - previous.connect(inputGate, methods.connection.ALL_TO_ALL); - previous.connect(outputGate, methods.connection.ALL_TO_ALL); - previous.connect(forgetGate, methods.connection.ALL_TO_ALL); - - // Set up internal connections - memoryCell.connect(inputGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(forgetGate, methods.connection.ALL_TO_ALL); - memoryCell.connect(outputGate, methods.connection.ALL_TO_ALL); - var forget = memoryCell.connect(memoryCell, methods.connection.ONE_TO_ONE); - var output = memoryCell.connect(outputBlock, methods.connection.ALL_TO_ALL); - - // Set up gates - inputGate.gate(input, methods.gating.INPUT); - forgetGate.gate(forget, methods.gating.SELF); - outputGate.gate(output, methods.gating.OUTPUT); - - // Input to all memory cells - if (options.inputToDeep && i > 0) { - let input = inputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - // Optional connections - if (options.memoryToMemory) { - let input = memoryCell.connect(memoryCell, methods.connection.ALL_TO_ELSE); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToMemory) { - let input = outputLayer.connect(memoryCell, methods.connection.ALL_TO_ALL); - inputGate.gate(input, methods.gating.INPUT); - } - - if (options.outputToGates) { - outputLayer.connect(inputGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(forgetGate, methods.connection.ALL_TO_ALL); - outputLayer.connect(outputGate, methods.connection.ALL_TO_ALL); - } - - // Add to array - nodes.push(inputGate); - nodes.push(forgetGate); - nodes.push(memoryCell); - nodes.push(outputGate); - if (i !== blocks.length - 1) nodes.push(outputBlock); - - previous = outputBlock; - } - - // input to output direct connection - if (options.inputToOutput) { - inputLayer.connect(outputLayer, methods.connection.ALL_TO_ALL); - } - - nodes.push(outputLayer); - return architect.Construct(nodes); - }, - - /** - * Creates a gated recurrent unit network - */ - GRU: function () { - var args = Array.prototype.slice.call(arguments); - if (args.length < 3) { - throw new Error('not enough layers (minimum 3) !!'); - } - - var inputLayer = new Group(args.shift()); // first argument - var outputLayer = new Group(args.pop()); // last argument - var blocks = args; // all the arguments in the middle - - var nodes = []; - nodes.push(inputLayer); - - var previous = inputLayer; - for (var i = 0; i < blocks.length; i++) { - var layer = new Layer.GRU(blocks[i]); - previous.connect(layer); - previous = layer; - - nodes.push(layer); - } - - previous.connect(outputLayer); - nodes.push(outputLayer); - - return architect.Construct(nodes); - }, - - /** - * Creates a hopfield network of the given size - */ - Hopfield: function (size) { - var input = new Group(size); - var output = new Group(size); - - input.connect(output, methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - squash: methods.activation.STEP, - type: 'output' - }); - - var network = new architect.Construct([input, output]); - - return network; - }, - - /** - * Creates a NARX network (remember previous inputs/outputs) - */ - NARX: function (inputSize, hiddenLayers, outputSize, previousInput, previousOutput) { - if (!Array.isArray(hiddenLayers)) { - hiddenLayers = [hiddenLayers]; - } - - var nodes = []; - - var input = new Layer.Dense(inputSize); - var inputMemory = new Layer.Memory(inputSize, previousInput); - var hidden = []; - var output = new Layer.Dense(outputSize); - var outputMemory = new Layer.Memory(outputSize, previousOutput); - - nodes.push(input); - nodes.push(outputMemory); - - for (var i = 0; i < hiddenLayers.length; i++) { - var hiddenLayer = new Layer.Dense(hiddenLayers[i]); - hidden.push(hiddenLayer); - nodes.push(hiddenLayer); - if (typeof hidden[i - 1] !== 'undefined') { - hidden[i - 1].connect(hiddenLayer, methods.connection.ALL_TO_ALL); - } - } - - nodes.push(inputMemory); - nodes.push(output); - - input.connect(hidden[0], methods.connection.ALL_TO_ALL); - input.connect(inputMemory, methods.connection.ONE_TO_ONE, 1); - inputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - hidden[hidden.length - 1].connect(output, methods.connection.ALL_TO_ALL); - output.connect(outputMemory, methods.connection.ONE_TO_ONE, 1); - outputMemory.connect(hidden[0], methods.connection.ALL_TO_ALL); - - input.set({ - type: 'input' - }); - output.set({ - type: 'output' - }); - - return architect.Construct(nodes); - } -}; - -/* Export */ -module.exports = architect; - - -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { - -/******************************************************************************* - WORKERS -*******************************************************************************/ - -var workers = { - node: { - TestWorker: __webpack_require__(20) - }, - browser: { - TestWorker: __webpack_require__(24) - } -}; - -/** Export */ -module.exports = workers; - - -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var cp = __webpack_require__(21); -var path = __webpack_require__(22); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - this.worker = cp.fork(path.join(__dirname, '/worker')); - - this.worker.send({ set: dataSet, cost: cost.name }); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: serialized[0], - states: serialized[1], - conns: serialized[2] - }; - - var _that = this.worker; - this.worker.on('message', function callback (e) { - _that.removeListener('message', callback); - resolve(e); - }); - - this.worker.send(data); - }); - }, - - terminate: function () { - this.worker.kill(); - } -}; - - -/***/ }), -/* 21 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_21__; - -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -/* WEBPACK VAR INJECTION */(function(process) {// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -// resolves . and .. elements in a path array with directory names there -// must be no slashes, empty elements, or device names (c:\) in the array -// (so also no leading and trailing slashes - it does not distinguish -// relative and absolute paths) -function normalizeArray(parts, allowAboveRoot) { - // if the path tries to go above the root, `up` ends up > 0 - var up = 0; - for (var i = parts.length - 1; i >= 0; i--) { - var last = parts[i]; - if (last === '.') { - parts.splice(i, 1); - } else if (last === '..') { - parts.splice(i, 1); - up++; - } else if (up) { - parts.splice(i, 1); - up--; - } - } - - // if the path is allowed to go above the root, restore leading ..s - if (allowAboveRoot) { - for (; up--; up) { - parts.unshift('..'); - } - } - - return parts; -} - -// Split a filename into [root, dir, basename, ext], unix version -// 'root' is just a slash, or nothing. -var splitPathRe = - /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; -var splitPath = function(filename) { - return splitPathRe.exec(filename).slice(1); -}; - -// path.resolve([from ...], to) -// posix version -exports.resolve = function() { - var resolvedPath = '', - resolvedAbsolute = false; - - for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { - var path = (i >= 0) ? arguments[i] : process.cwd(); - - // Skip empty and invalid entries - if (typeof path !== 'string') { - throw new TypeError('Arguments to path.resolve must be strings'); - } else if (!path) { - continue; - } - - resolvedPath = path + '/' + resolvedPath; - resolvedAbsolute = path.charAt(0) === '/'; - } - - // At this point the path should be resolved to a full absolute path, but - // handle relative paths to be safe (might happen when process.cwd() fails) - - // Normalize the path - resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { - return !!p; - }), !resolvedAbsolute).join('/'); - - return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; -}; - -// path.normalize(path) -// posix version -exports.normalize = function(path) { - var isAbsolute = exports.isAbsolute(path), - trailingSlash = substr(path, -1) === '/'; - - // Normalize the path - path = normalizeArray(filter(path.split('/'), function(p) { - return !!p; - }), !isAbsolute).join('/'); - - if (!path && !isAbsolute) { - path = '.'; - } - if (path && trailingSlash) { - path += '/'; - } - - return (isAbsolute ? '/' : '') + path; -}; - -// posix version -exports.isAbsolute = function(path) { - return path.charAt(0) === '/'; -}; - -// posix version -exports.join = function() { - var paths = Array.prototype.slice.call(arguments, 0); - return exports.normalize(filter(paths, function(p, index) { - if (typeof p !== 'string') { - throw new TypeError('Arguments to path.join must be strings'); - } - return p; - }).join('/')); -}; - - -// path.relative(from, to) -// posix version -exports.relative = function(from, to) { - from = exports.resolve(from).substr(1); - to = exports.resolve(to).substr(1); - - function trim(arr) { - var start = 0; - for (; start < arr.length; start++) { - if (arr[start] !== '') break; - } - - var end = arr.length - 1; - for (; end >= 0; end--) { - if (arr[end] !== '') break; - } - - if (start > end) return []; - return arr.slice(start, end - start + 1); - } - - var fromParts = trim(from.split('/')); - var toParts = trim(to.split('/')); - - var length = Math.min(fromParts.length, toParts.length); - var samePartsLength = length; - for (var i = 0; i < length; i++) { - if (fromParts[i] !== toParts[i]) { - samePartsLength = i; - break; - } - } - - var outputParts = []; - for (var i = samePartsLength; i < fromParts.length; i++) { - outputParts.push('..'); - } - - outputParts = outputParts.concat(toParts.slice(samePartsLength)); - - return outputParts.join('/'); -}; - -exports.sep = '/'; -exports.delimiter = ':'; - -exports.dirname = function(path) { - var result = splitPath(path), - root = result[0], - dir = result[1]; - - if (!root && !dir) { - // No dirname whatsoever - return '.'; - } - - if (dir) { - // It has a dirname, strip trailing slash - dir = dir.substr(0, dir.length - 1); - } - - return root + dir; -}; - - -exports.basename = function(path, ext) { - var f = splitPath(path)[2]; - // TODO: make this comparison case-insensitive on windows? - if (ext && f.substr(-1 * ext.length) === ext) { - f = f.substr(0, f.length - ext.length); - } - return f; -}; - - -exports.extname = function(path) { - return splitPath(path)[3]; -}; - -function filter (xs, f) { - if (xs.filter) return xs.filter(f); - var res = []; - for (var i = 0; i < xs.length; i++) { - if (f(xs[i], i, xs)) res.push(xs[i]); - } - return res; -} - -// String.prototype.substr - negative index don't work in IE8 -var substr = 'ab'.substr(-1) === 'b' - ? function (str, start, len) { return str.substr(start, len) } - : function (str, start, len) { - if (start < 0) start = str.length + start; - return str.substr(start, len); - } -; - -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(23))) - -/***/ }), -/* 23 */ -/***/ (function(module, exports) { - -// shim for using process in browser -var process = module.exports = {}; - -// cached from whatever global is present so that test runners that stub it -// don't break things. But we need to wrap it in a try catch in case it is -// wrapped in strict mode code which doesn't define any globals. It's inside a -// function because try/catches deoptimize in certain engines. - -var cachedSetTimeout; -var cachedClearTimeout; - -function defaultSetTimout() { - throw new Error('setTimeout has not been defined'); -} -function defaultClearTimeout () { - throw new Error('clearTimeout has not been defined'); -} -(function () { - try { - if (typeof setTimeout === 'function') { - cachedSetTimeout = setTimeout; - } else { - cachedSetTimeout = defaultSetTimout; - } - } catch (e) { - cachedSetTimeout = defaultSetTimout; - } - try { - if (typeof clearTimeout === 'function') { - cachedClearTimeout = clearTimeout; - } else { - cachedClearTimeout = defaultClearTimeout; - } - } catch (e) { - cachedClearTimeout = defaultClearTimeout; - } -} ()) -function runTimeout(fun) { - if (cachedSetTimeout === setTimeout) { - //normal enviroments in sane situations - return setTimeout(fun, 0); - } - // if setTimeout wasn't available but was latter defined - if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { - cachedSetTimeout = setTimeout; - return setTimeout(fun, 0); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedSetTimeout(fun, 0); - } catch(e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedSetTimeout.call(null, fun, 0); - } catch(e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error - return cachedSetTimeout.call(this, fun, 0); - } - } - - -} -function runClearTimeout(marker) { - if (cachedClearTimeout === clearTimeout) { - //normal enviroments in sane situations - return clearTimeout(marker); - } - // if clearTimeout wasn't available but was latter defined - if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { - cachedClearTimeout = clearTimeout; - return clearTimeout(marker); - } - try { - // when when somebody has screwed with setTimeout but no I.E. maddness - return cachedClearTimeout(marker); - } catch (e){ - try { - // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally - return cachedClearTimeout.call(null, marker); - } catch (e){ - // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. - // Some versions of I.E. have different rules for clearTimeout vs setTimeout - return cachedClearTimeout.call(this, marker); - } - } - - - -} -var queue = []; -var draining = false; -var currentQueue; -var queueIndex = -1; - -function cleanUpNextTick() { - if (!draining || !currentQueue) { - return; - } - draining = false; - if (currentQueue.length) { - queue = currentQueue.concat(queue); - } else { - queueIndex = -1; - } - if (queue.length) { - drainQueue(); - } -} - -function drainQueue() { - if (draining) { - return; - } - var timeout = runTimeout(cleanUpNextTick); - draining = true; - - var len = queue.length; - while(len) { - currentQueue = queue; - queue = []; - while (++queueIndex < len) { - if (currentQueue) { - currentQueue[queueIndex].run(); - } - } - queueIndex = -1; - len = queue.length; - } - currentQueue = null; - draining = false; - runClearTimeout(timeout); -} - -process.nextTick = function (fun) { - var args = new Array(arguments.length - 1); - if (arguments.length > 1) { - for (var i = 1; i < arguments.length; i++) { - args[i - 1] = arguments[i]; - } - } - queue.push(new Item(fun, args)); - if (queue.length === 1 && !draining) { - runTimeout(drainQueue); - } -}; - -// v8 likes predictible objects -function Item(fun, array) { - this.fun = fun; - this.array = array; -} -Item.prototype.run = function () { - this.fun.apply(null, this.array); -}; -process.title = 'browser'; -process.browser = true; -process.env = {}; -process.argv = []; -process.version = ''; // empty string to avoid regexp issues -process.versions = {}; - -function noop() {} - -process.on = noop; -process.addListener = noop; -process.once = noop; -process.off = noop; -process.removeListener = noop; -process.removeAllListeners = noop; -process.emit = noop; -process.prependListener = noop; -process.prependOnceListener = noop; - -process.listeners = function (name) { return [] } - -process.binding = function (name) { - throw new Error('process.binding is not supported'); -}; - -process.cwd = function () { return '/' }; -process.chdir = function (dir) { - throw new Error('process.chdir is not supported'); -}; -process.umask = function() { return 0; }; - - -/***/ }), -/* 24 */ -/***/ (function(module, exports, __webpack_require__) { - -/* Export */ -module.exports = TestWorker; - -/* Import */ -var multi = __webpack_require__(5); - -/******************************************************************************* - WEBWORKER -*******************************************************************************/ - -function TestWorker (dataSet, cost) { - var blob = new Blob([this._createBlobString(cost)]); - this.url = window.URL.createObjectURL(blob); - this.worker = new Worker(this.url); - - var data = { set: new Float64Array(dataSet).buffer }; - this.worker.postMessage(data, [data.set]); -} - -TestWorker.prototype = { - evaluate: function (network) { - return new Promise((resolve, reject) => { - var serialized = network.serialize(); - - var data = { - activations: new Float64Array(serialized[0]).buffer, - states: new Float64Array(serialized[1]).buffer, - conns: new Float64Array(serialized[2]).buffer - }; - - this.worker.onmessage = function (e) { - var error = new Float64Array(e.data.buffer)[0]; - resolve(error); - }; - - this.worker.postMessage(data, [data.activations, data.states, data.conns]); - }); - }, - - terminate: function () { - this.worker.terminate(); - window.URL.revokeObjectURL(this.url); - }, - - _createBlobString: function (cost) { - var source = ` - var F = [${multi.activations.toString()}]; - var cost = ${cost.toString()}; - var multi = { - deserializeDataSet: ${multi.deserializeDataSet.toString()}, - testSerializedSet: ${multi.testSerializedSet.toString()}, - activateSerializedNetwork: ${multi.activateSerializedNetwork.toString()} - }; - - this.onmessage = function (e) { - if(typeof e.data.set === 'undefined'){ - var A = new Float64Array(e.data.activations); - var S = new Float64Array(e.data.states); - var data = new Float64Array(e.data.conns); - - var error = multi.testSerializedSet(set, cost, A, S, data, F); - - var answer = { buffer: new Float64Array([error ]).buffer }; - postMessage(answer, [answer.buffer]); - } else { - set = multi.deserializeDataSet(new Float64Array(e.data.set)); - } - };`; - - return source; - } -}; - - -/***/ }), -/* 25 */ -/***/ (function(module, exports) { - -module.exports = __WEBPACK_EXTERNAL_MODULE_25__; - -/***/ }) -/******/ ]); -}); \ No newline at end of file diff --git a/node_modules/neataptic/docs/css/base.css b/node_modules/neataptic/docs/css/base.css deleted file mode 100644 index 0d84f8a..0000000 --- a/node_modules/neataptic/docs/css/base.css +++ /dev/null @@ -1,319 +0,0 @@ -body { - padding-top: 70px; - background: url(../img/grid.png) repeat-x; - background-attachment: fixed; - background-color: #f8f8f8; -} - -body > .container { - min-height: 400px; -} - -ul.nav .main { - font-weight: bold; -} - -.col-md-3 { - padding-left: 0; -} - -.col-md-9 { - padding-bottom: 100px; -} - -.source-links { - float: right; -} - -.col-md-9 img { - max-width: 100%; - display: inline-block; - padding: 4px; - line-height: 1.428571429; - background-color: #fff; - border: 1px solid #ddd; - border-radius: 4px; - margin: 20px auto 30px auto; -} - -/* - * The code below adds some padding to the top of the current anchor target so - * that, when navigating to it, the header isn't hidden by the navbar at the - * top. This is especially complicated because we want to *remove* the padding - * after navigation so that hovering over the header shows the permalink icon - * correctly. Thus, we create a CSS animation to remove the extra padding after - * a second. We have two animations so that navigating to an anchor within the - * page always restarts the animation. - * - * See for more details. - */ -:target::before { - content: ""; - display: block; - margin-top: -75px; - height: 75px; - pointer-events: none; - animation: 0s 1s forwards collapse-anchor-padding-1; -} - -.clicky :target::before { - animation-name: collapse-anchor-padding-2; -} - -@keyframes collapse-anchor-padding-1 { - to { - margin-top: 0; - height: 0; - } -} - -@keyframes collapse-anchor-padding-2 { - to { - margin-top: 0; - height: 0; - } -} - -h1 { - color: #444; - font-weight: 400; - font-size: 42px; -} - -h2, h3, h4, h5, h6 { - color: #444; - font-weight: 300; -} - -hr { - border-top: 1px solid #aaa; -} - -pre, .rst-content tt { - max-width: 100%; - background: #fff; - border: solid 1px #e1e4e5; - color: #333; - overflow-x: auto; -} - -code.code-large, .rst-content tt.code-large { - font-size: 90%; -} - -code { - padding: 2px 5px; - background: #fff; - border: solid 1px #e1e4e5; - color: #333; - white-space: pre-wrap; - word-wrap: break-word; -} - -pre code { - background: transparent; - border: none; - white-space: pre; - word-wrap: normal; - font-family: monospace,serif; - font-size: 12px; -} - -a code { - color: #2FA4E7; -} - -a:hover code, a:focus code { - color: #157AB5; -} - -footer { - margin-top: 30px; - margin-bottom: 10px; - text-align: center; - font-weight: 200; -} - -.modal-dialog { - margin-top: 60px; -} - -/* - * Side navigation - * - * Scrollspy and affixed enhanced navigation to highlight sections and secondary - * sections of docs content. - */ - -/* By default it's not affixed in mobile views, so undo that */ -.bs-sidebar.affix { /* csslint allow: adjoining-classes */ - position: static; -} - -.bs-sidebar.well { /* csslint allow: adjoining-classes */ - padding: 0; - max-height: 90%; - overflow-y: auto; -} - -/* First level of nav */ -.bs-sidenav { - padding-top: 10px; - padding-bottom: 10px; - border-radius: 5px; -} - -/* All levels of nav */ -.bs-sidebar .nav > li > a { - display: block; - padding: 5px 20px; - z-index: 1; -} -.bs-sidebar .nav > li > a:hover, -.bs-sidebar .nav > li > a:focus { - text-decoration: none; - border-right: 1px solid; -} -.bs-sidebar .nav > .active > a, -.bs-sidebar .nav > .active:hover > a, -.bs-sidebar .nav > .active:focus > a { - font-weight: bold; - background-color: transparent; - border-right: 1px solid; -} - -/* Nav: second level (shown on .active) */ -.bs-sidebar .nav .nav { - display: none; /* Hide by default, but at >768px, show it */ - margin-bottom: 8px; -} -.bs-sidebar .nav .nav > li > a { - padding-top: 3px; - padding-bottom: 3px; - padding-left: 30px; - font-size: 90%; -} - -/* Show and affix the side nav when space allows it */ -@media (min-width: 992px) { - .bs-sidebar .nav > .active > ul { - display: block; - } - /* Widen the fixed sidebar */ - .bs-sidebar.affix, /* csslint allow: adjoining-classes */ - .bs-sidebar.affix-bottom { /* csslint allow: adjoining-classes */ - width: 213px; - } - .bs-sidebar.affix { /* csslint allow: adjoining-classes */ - position: fixed; /* Undo the static from mobile first approach */ - top: 80px; - } - .bs-sidebar.affix-bottom { /* csslint allow: adjoining-classes */ - position: absolute; /* Undo the static from mobile first approach */ - } - .bs-sidebar.affix-bottom .bs-sidenav, /* csslint allow: adjoining-classes */ - .bs-sidebar.affix .bs-sidenav { /* csslint allow: adjoining-classes */ - margin-top: 0; - margin-bottom: 0; - } -} -@media (min-width: 1200px) { - /* Widen the fixed sidebar again */ - .bs-sidebar.affix-bottom, /* csslint allow: adjoining-classes */ - .bs-sidebar.affix { /* csslint allow: adjoining-classes */ - width: 263px; - } -} - -.headerlink { - font-family: FontAwesome; - font-size: 14px; - display: none; - padding-left: .5em; -} - -h1:hover .headerlink, h2:hover .headerlink, h3:hover .headerlink, h4:hover .headerlink, h5:hover .headerlink, h6:hover .headerlink{ - display:inline-block; -} - - - -.admonition { - padding: 15px; - margin-bottom: 20px; - border: 1px solid transparent; - border-radius: 4px; - text-align: left; -} - -.admonition.note { /* csslint allow: adjoining-classes */ - color: #3a87ad; - background-color: #d9edf7; - border-color: #bce8f1; -} - -.admonition.warning { /* csslint allow: adjoining-classes */ - color: #c09853; - background-color: #fcf8e3; - border-color: #fbeed5; -} - -.admonition.danger { /* csslint allow: adjoining-classes */ - color: #b94a48; - background-color: #f2dede; - border-color: #eed3d7; -} - -.admonition-title { - font-weight: bold; - text-align: left; -} - - -.dropdown-submenu { - position: relative; -} - -.dropdown-submenu>.dropdown-menu { - top: 0; - left: 100%; - margin-top: -6px; - margin-left: -1px; - -webkit-border-radius: 0 6px 6px 6px; - -moz-border-radius: 0 6px 6px; - border-radius: 0 6px 6px 6px; -} - -.dropdown-submenu:hover>.dropdown-menu { - display: block; -} - -.dropdown-submenu>a:after { - display: block; - content: " "; - float: right; - width: 0; - height: 0; - border-color: transparent; - border-style: solid; - border-width: 5px 0 5px 5px; - border-left-color: #ccc; - margin-top: 5px; - margin-right: -10px; -} - -.dropdown-submenu:hover>a:after { - border-left-color: #fff; -} - -.dropdown-submenu.pull-left { /* csslint allow: adjoining-classes */ - float: none; -} - -.dropdown-submenu.pull-left>.dropdown-menu { /* csslint allow: adjoining-classes */ - left: -100%; - margin-left: 10px; - -webkit-border-radius: 6px 0 6px 6px; - -moz-border-radius: 6px 0 6px 6px; - border-radius: 6px 0 6px 6px; -} diff --git a/node_modules/neataptic/docs/css/bootstrap-custom.min.css b/node_modules/neataptic/docs/css/bootstrap-custom.min.css deleted file mode 100644 index d85b1dc..0000000 --- a/node_modules/neataptic/docs/css/bootstrap-custom.min.css +++ /dev/null @@ -1 +0,0 @@ -/*! normalize.css v2.1.3 | MIT License | git.io/normalize */article,aside,details,figcaption,figure,footer,header,hgroup,main,nav,section,summary{display:block}audio,canvas,video{display:inline-block}audio:not([controls]){display:none;height:0}[hidden],template{display:none}html{font-family:sans-serif;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{margin:0}a{background:transparent}a:focus{outline:thin dotted}a:active,a:hover{outline:0}h1{margin:.67em 0;font-size:2em}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}hr{height:0;-moz-box-sizing:content-box;box-sizing:content-box}mark{color:#000;background:#ff0}code,kbd,pre,samp{font-family:monospace,serif;font-size:1em}pre{white-space:pre-wrap}q{quotes:"\201C" "\201D" "\2018" "\2019"}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:0}fieldset{padding:.35em .625em .75em;margin:0 2px;border:1px solid #c0c0c0}legend{padding:0;border:0}button,input,select,textarea{margin:0;font-family:inherit;font-size:100%}button,input{line-height:normal}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button}button[disabled],html input[disabled]{cursor:default}input[type="checkbox"],input[type="radio"]{padding:0;box-sizing:border-box}input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0}textarea{overflow:auto;vertical-align:top}table{border-collapse:collapse;border-spacing:0}@media print{*{color:#000!important;text-shadow:none!important;background:transparent!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href) ")"}abbr[title]:after{content:" (" attr(title) ")"}a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}@page{margin:2cm .5cm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}select{background:#fff!important}.navbar{display:none}.table td,.table th{background-color:#fff!important}.btn>.caret,.dropup>.btn>.caret{border-top-color:#000!important}.label{border:1px solid #000}.table{border-collapse:collapse!important}.table-bordered th,.table-bordered td{border:1px solid #ddd!important}}*,*:before,*:after{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}html{font-size:62.5%;-webkit-tap-highlight-color:rgba(0,0,0,0)}body{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:1.428571429;color:#555;background-color:#fff}input,button,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit}a{color:#2fa4e7;text-decoration:none}a:hover,a:focus{color:#157ab5;text-decoration:underline}a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}img{vertical-align:middle}.img-responsive{display:block;height:auto;max-width:100%}.img-rounded{border-radius:6px}.img-thumbnail{display:inline-block;height:auto;max-width:100%;padding:4px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.img-circle{border-radius:50%}hr{margin-top:20px;margin-bottom:20px;border:0;border-top:1px solid #eee}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);border:0}h1,h2,h3,h4,h5,h6,.h1,.h2,.h3,.h4,.h5,.h6{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:500;line-height:1.1;color:#317eac}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small,.h1 small,.h2 small,.h3 small,.h4 small,.h5 small,.h6 small,h1 .small,h2 .small,h3 .small,h4 .small,h5 .small,h6 .small,.h1 .small,.h2 .small,.h3 .small,.h4 .small,.h5 .small,.h6 .small{font-weight:normal;line-height:1;color:#999}h1,h2,h3{margin-top:20px;margin-bottom:10px}h1 small,h2 small,h3 small,h1 .small,h2 .small,h3 .small{font-size:65%}h4,h5,h6{margin-top:10px;margin-bottom:10px}h4 small,h5 small,h6 small,h4 .small,h5 .small,h6 .small{font-size:75%}h1,.h1{font-size:36px}h2,.h2{font-size:30px}h3,.h3{font-size:24px}h4,.h4{font-size:18px}h5,.h5{font-size:14px}h6,.h6{font-size:12px}p{margin:0 0 10px}.lead{margin-bottom:20px;font-size:16px;font-weight:200;line-height:1.4}@media(min-width:768px){.lead{font-size:21px}}small,.small{font-size:85%}cite{font-style:normal}.text-muted{color:#999}.text-primary{color:#2fa4e7}.text-primary:hover{color:#178acc}.text-warning{color:#c09853}.text-warning:hover{color:#a47e3c}.text-danger{color:#b94a48}.text-danger:hover{color:#953b39}.text-success{color:#468847}.text-success:hover{color:#356635}.text-info{color:#3a87ad}.text-info:hover{color:#2d6987}.text-left{text-align:left}.text-right{text-align:right}.text-center{text-align:center}.page-header{padding-bottom:9px;margin:40px 0 20px;border-bottom:1px solid #eee}ul,ol{margin-top:0;margin-bottom:10px}ul ul,ol ul,ul ol,ol ol{margin-bottom:0}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline>li{display:inline-block;padding-right:5px;padding-left:5px}.list-inline>li:first-child{padding-left:0}dl{margin-top:0;margin-bottom:20px}dt,dd{line-height:1.428571429}dt{font-weight:bold}dd{margin-left:0}@media(min-width:768px){.dl-horizontal dt{float:left;width:160px;overflow:hidden;clear:left;text-align:right;text-overflow:ellipsis;white-space:nowrap}.dl-horizontal dd{margin-left:180px}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}.dl-horizontal dd:before,.dl-horizontal dd:after{display:table;content:" "}.dl-horizontal dd:after{clear:both}}abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999}.initialism{font-size:90%;text-transform:uppercase}blockquote{padding:10px 20px;margin:0 0 20px;border-left:5px solid #eee}blockquote p{font-size:17.5px;font-weight:300;line-height:1.25}blockquote p:last-child{margin-bottom:0}blockquote small,blockquote .small{display:block;line-height:1.428571429;color:#999}blockquote small:before,blockquote .small:before{content:'\2014 \00A0'}blockquote.pull-right{padding-right:15px;padding-left:0;border-right:5px solid #eee;border-left:0}blockquote.pull-right p,blockquote.pull-right small,blockquote.pull-right .small{text-align:right}blockquote.pull-right small:before,blockquote.pull-right .small:before{content:''}blockquote.pull-right small:after,blockquote.pull-right .small:after{content:'\00A0 \2014'}blockquote:before,blockquote:after{content:""}address{margin-bottom:20px;font-style:normal;line-height:1.428571429}code,kbd,pre,samp{font-family:Menlo,Monaco,Consolas,"Courier New",monospace}code{padding:2px 4px;font-size:90%;color:#c7254e;white-space:nowrap;background-color:#f9f2f4;border-radius:4px}pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:1.428571429;color:#333;word-break:break-all;word-wrap:break-word;background-color:#f5f5f5;border:1px solid #ccc;border-radius:4px}pre code{padding:0;font-size:inherit;color:inherit;white-space:pre-wrap;background-color:transparent;border-radius:0}.pre-scrollable{max-height:340px;overflow-y:scroll}.container{padding-right:15px;padding-left:15px;margin-right:auto;margin-left:auto}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}.container:before,.container:after{display:table;content:" "}.container:after{clear:both}@media(min-width:768px){.container{width:750px}}@media(min-width:992px){.container{width:970px}}@media(min-width:1200px){.container{width:1170px}}.row{margin-right:-15px;margin-left:-15px}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.row:before,.row:after{display:table;content:" "}.row:after{clear:both}.col-xs-1,.col-sm-1,.col-md-1,.col-lg-1,.col-xs-2,.col-sm-2,.col-md-2,.col-lg-2,.col-xs-3,.col-sm-3,.col-md-3,.col-lg-3,.col-xs-4,.col-sm-4,.col-md-4,.col-lg-4,.col-xs-5,.col-sm-5,.col-md-5,.col-lg-5,.col-xs-6,.col-sm-6,.col-md-6,.col-lg-6,.col-xs-7,.col-sm-7,.col-md-7,.col-lg-7,.col-xs-8,.col-sm-8,.col-md-8,.col-lg-8,.col-xs-9,.col-sm-9,.col-md-9,.col-lg-9,.col-xs-10,.col-sm-10,.col-md-10,.col-lg-10,.col-xs-11,.col-sm-11,.col-md-11,.col-lg-11,.col-xs-12,.col-sm-12,.col-md-12,.col-lg-12{position:relative;min-height:1px;padding-right:15px;padding-left:15px}.col-xs-1,.col-xs-2,.col-xs-3,.col-xs-4,.col-xs-5,.col-xs-6,.col-xs-7,.col-xs-8,.col-xs-9,.col-xs-10,.col-xs-11,.col-xs-12{float:left}.col-xs-12{width:100%}.col-xs-11{width:91.66666666666666%}.col-xs-10{width:83.33333333333334%}.col-xs-9{width:75%}.col-xs-8{width:66.66666666666666%}.col-xs-7{width:58.333333333333336%}.col-xs-6{width:50%}.col-xs-5{width:41.66666666666667%}.col-xs-4{width:33.33333333333333%}.col-xs-3{width:25%}.col-xs-2{width:16.666666666666664%}.col-xs-1{width:8.333333333333332%}.col-xs-pull-12{right:100%}.col-xs-pull-11{right:91.66666666666666%}.col-xs-pull-10{right:83.33333333333334%}.col-xs-pull-9{right:75%}.col-xs-pull-8{right:66.66666666666666%}.col-xs-pull-7{right:58.333333333333336%}.col-xs-pull-6{right:50%}.col-xs-pull-5{right:41.66666666666667%}.col-xs-pull-4{right:33.33333333333333%}.col-xs-pull-3{right:25%}.col-xs-pull-2{right:16.666666666666664%}.col-xs-pull-1{right:8.333333333333332%}.col-xs-pull-0{right:0}.col-xs-push-12{left:100%}.col-xs-push-11{left:91.66666666666666%}.col-xs-push-10{left:83.33333333333334%}.col-xs-push-9{left:75%}.col-xs-push-8{left:66.66666666666666%}.col-xs-push-7{left:58.333333333333336%}.col-xs-push-6{left:50%}.col-xs-push-5{left:41.66666666666667%}.col-xs-push-4{left:33.33333333333333%}.col-xs-push-3{left:25%}.col-xs-push-2{left:16.666666666666664%}.col-xs-push-1{left:8.333333333333332%}.col-xs-push-0{left:0}.col-xs-offset-12{margin-left:100%}.col-xs-offset-11{margin-left:91.66666666666666%}.col-xs-offset-10{margin-left:83.33333333333334%}.col-xs-offset-9{margin-left:75%}.col-xs-offset-8{margin-left:66.66666666666666%}.col-xs-offset-7{margin-left:58.333333333333336%}.col-xs-offset-6{margin-left:50%}.col-xs-offset-5{margin-left:41.66666666666667%}.col-xs-offset-4{margin-left:33.33333333333333%}.col-xs-offset-3{margin-left:25%}.col-xs-offset-2{margin-left:16.666666666666664%}.col-xs-offset-1{margin-left:8.333333333333332%}.col-xs-offset-0{margin-left:0}@media(min-width:768px){.col-sm-1,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-10,.col-sm-11,.col-sm-12{float:left}.col-sm-12{width:100%}.col-sm-11{width:91.66666666666666%}.col-sm-10{width:83.33333333333334%}.col-sm-9{width:75%}.col-sm-8{width:66.66666666666666%}.col-sm-7{width:58.333333333333336%}.col-sm-6{width:50%}.col-sm-5{width:41.66666666666667%}.col-sm-4{width:33.33333333333333%}.col-sm-3{width:25%}.col-sm-2{width:16.666666666666664%}.col-sm-1{width:8.333333333333332%}.col-sm-pull-12{right:100%}.col-sm-pull-11{right:91.66666666666666%}.col-sm-pull-10{right:83.33333333333334%}.col-sm-pull-9{right:75%}.col-sm-pull-8{right:66.66666666666666%}.col-sm-pull-7{right:58.333333333333336%}.col-sm-pull-6{right:50%}.col-sm-pull-5{right:41.66666666666667%}.col-sm-pull-4{right:33.33333333333333%}.col-sm-pull-3{right:25%}.col-sm-pull-2{right:16.666666666666664%}.col-sm-pull-1{right:8.333333333333332%}.col-sm-pull-0{right:0}.col-sm-push-12{left:100%}.col-sm-push-11{left:91.66666666666666%}.col-sm-push-10{left:83.33333333333334%}.col-sm-push-9{left:75%}.col-sm-push-8{left:66.66666666666666%}.col-sm-push-7{left:58.333333333333336%}.col-sm-push-6{left:50%}.col-sm-push-5{left:41.66666666666667%}.col-sm-push-4{left:33.33333333333333%}.col-sm-push-3{left:25%}.col-sm-push-2{left:16.666666666666664%}.col-sm-push-1{left:8.333333333333332%}.col-sm-push-0{left:0}.col-sm-offset-12{margin-left:100%}.col-sm-offset-11{margin-left:91.66666666666666%}.col-sm-offset-10{margin-left:83.33333333333334%}.col-sm-offset-9{margin-left:75%}.col-sm-offset-8{margin-left:66.66666666666666%}.col-sm-offset-7{margin-left:58.333333333333336%}.col-sm-offset-6{margin-left:50%}.col-sm-offset-5{margin-left:41.66666666666667%}.col-sm-offset-4{margin-left:33.33333333333333%}.col-sm-offset-3{margin-left:25%}.col-sm-offset-2{margin-left:16.666666666666664%}.col-sm-offset-1{margin-left:8.333333333333332%}.col-sm-offset-0{margin-left:0}}@media(min-width:992px){.col-md-1,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-10,.col-md-11,.col-md-12{float:left}.col-md-12{width:100%}.col-md-11{width:91.66666666666666%}.col-md-10{width:83.33333333333334%}.col-md-9{width:75%}.col-md-8{width:66.66666666666666%}.col-md-7{width:58.333333333333336%}.col-md-6{width:50%}.col-md-5{width:41.66666666666667%}.col-md-4{width:33.33333333333333%}.col-md-3{width:25%}.col-md-2{width:16.666666666666664%}.col-md-1{width:8.333333333333332%}.col-md-pull-12{right:100%}.col-md-pull-11{right:91.66666666666666%}.col-md-pull-10{right:83.33333333333334%}.col-md-pull-9{right:75%}.col-md-pull-8{right:66.66666666666666%}.col-md-pull-7{right:58.333333333333336%}.col-md-pull-6{right:50%}.col-md-pull-5{right:41.66666666666667%}.col-md-pull-4{right:33.33333333333333%}.col-md-pull-3{right:25%}.col-md-pull-2{right:16.666666666666664%}.col-md-pull-1{right:8.333333333333332%}.col-md-pull-0{right:0}.col-md-push-12{left:100%}.col-md-push-11{left:91.66666666666666%}.col-md-push-10{left:83.33333333333334%}.col-md-push-9{left:75%}.col-md-push-8{left:66.66666666666666%}.col-md-push-7{left:58.333333333333336%}.col-md-push-6{left:50%}.col-md-push-5{left:41.66666666666667%}.col-md-push-4{left:33.33333333333333%}.col-md-push-3{left:25%}.col-md-push-2{left:16.666666666666664%}.col-md-push-1{left:8.333333333333332%}.col-md-push-0{left:0}.col-md-offset-12{margin-left:100%}.col-md-offset-11{margin-left:91.66666666666666%}.col-md-offset-10{margin-left:83.33333333333334%}.col-md-offset-9{margin-left:75%}.col-md-offset-8{margin-left:66.66666666666666%}.col-md-offset-7{margin-left:58.333333333333336%}.col-md-offset-6{margin-left:50%}.col-md-offset-5{margin-left:41.66666666666667%}.col-md-offset-4{margin-left:33.33333333333333%}.col-md-offset-3{margin-left:25%}.col-md-offset-2{margin-left:16.666666666666664%}.col-md-offset-1{margin-left:8.333333333333332%}.col-md-offset-0{margin-left:0}}@media(min-width:1200px){.col-lg-1,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-10,.col-lg-11,.col-lg-12{float:left}.col-lg-12{width:100%}.col-lg-11{width:91.66666666666666%}.col-lg-10{width:83.33333333333334%}.col-lg-9{width:75%}.col-lg-8{width:66.66666666666666%}.col-lg-7{width:58.333333333333336%}.col-lg-6{width:50%}.col-lg-5{width:41.66666666666667%}.col-lg-4{width:33.33333333333333%}.col-lg-3{width:25%}.col-lg-2{width:16.666666666666664%}.col-lg-1{width:8.333333333333332%}.col-lg-pull-12{right:100%}.col-lg-pull-11{right:91.66666666666666%}.col-lg-pull-10{right:83.33333333333334%}.col-lg-pull-9{right:75%}.col-lg-pull-8{right:66.66666666666666%}.col-lg-pull-7{right:58.333333333333336%}.col-lg-pull-6{right:50%}.col-lg-pull-5{right:41.66666666666667%}.col-lg-pull-4{right:33.33333333333333%}.col-lg-pull-3{right:25%}.col-lg-pull-2{right:16.666666666666664%}.col-lg-pull-1{right:8.333333333333332%}.col-lg-pull-0{right:0}.col-lg-push-12{left:100%}.col-lg-push-11{left:91.66666666666666%}.col-lg-push-10{left:83.33333333333334%}.col-lg-push-9{left:75%}.col-lg-push-8{left:66.66666666666666%}.col-lg-push-7{left:58.333333333333336%}.col-lg-push-6{left:50%}.col-lg-push-5{left:41.66666666666667%}.col-lg-push-4{left:33.33333333333333%}.col-lg-push-3{left:25%}.col-lg-push-2{left:16.666666666666664%}.col-lg-push-1{left:8.333333333333332%}.col-lg-push-0{left:0}.col-lg-offset-12{margin-left:100%}.col-lg-offset-11{margin-left:91.66666666666666%}.col-lg-offset-10{margin-left:83.33333333333334%}.col-lg-offset-9{margin-left:75%}.col-lg-offset-8{margin-left:66.66666666666666%}.col-lg-offset-7{margin-left:58.333333333333336%}.col-lg-offset-6{margin-left:50%}.col-lg-offset-5{margin-left:41.66666666666667%}.col-lg-offset-4{margin-left:33.33333333333333%}.col-lg-offset-3{margin-left:25%}.col-lg-offset-2{margin-left:16.666666666666664%}.col-lg-offset-1{margin-left:8.333333333333332%}.col-lg-offset-0{margin-left:0}}table{max-width:100%;background-color:transparent}th{text-align:left}.table{width:100%;margin-bottom:20px}.table>thead>tr>th,.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>td,.table>tbody>tr>td,.table>tfoot>tr>td{padding:8px;line-height:1.428571429;vertical-align:top;border-top:1px solid #ddd}.table>thead>tr>th{vertical-align:bottom;border-bottom:2px solid #ddd}.table>caption+thead>tr:first-child>th,.table>colgroup+thead>tr:first-child>th,.table>thead:first-child>tr:first-child>th,.table>caption+thead>tr:first-child>td,.table>colgroup+thead>tr:first-child>td,.table>thead:first-child>tr:first-child>td{border-top:0}.table>tbody+tbody{border-top:2px solid #ddd}.table .table{background-color:#fff}.table-condensed>thead>tr>th,.table-condensed>tbody>tr>th,.table-condensed>tfoot>tr>th,.table-condensed>thead>tr>td,.table-condensed>tbody>tr>td,.table-condensed>tfoot>tr>td{padding:5px}.table-bordered{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>tbody>tr>th,.table-bordered>tfoot>tr>th,.table-bordered>thead>tr>td,.table-bordered>tbody>tr>td,.table-bordered>tfoot>tr>td{border:1px solid #ddd}.table-bordered>thead>tr>th,.table-bordered>thead>tr>td{border-bottom-width:2px}.table-striped>tbody>tr:nth-child(odd)>td,.table-striped>tbody>tr:nth-child(odd)>th{background-color:#f9f9f9}.table-hover>tbody>tr:hover>td,.table-hover>tbody>tr:hover>th{background-color:#f5f5f5}table col[class*="col-"]{position:static;display:table-column;float:none}table td[class*="col-"],table th[class*="col-"]{display:table-cell;float:none}.table>thead>tr>.active,.table>tbody>tr>.active,.table>tfoot>tr>.active,.table>thead>.active>td,.table>tbody>.active>td,.table>tfoot>.active>td,.table>thead>.active>th,.table>tbody>.active>th,.table>tfoot>.active>th{background-color:#f5f5f5}.table-hover>tbody>tr>.active:hover,.table-hover>tbody>.active:hover>td,.table-hover>tbody>.active:hover>th{background-color:#e8e8e8}.table>thead>tr>.success,.table>tbody>tr>.success,.table>tfoot>tr>.success,.table>thead>.success>td,.table>tbody>.success>td,.table>tfoot>.success>td,.table>thead>.success>th,.table>tbody>.success>th,.table>tfoot>.success>th{background-color:#dff0d8}.table-hover>tbody>tr>.success:hover,.table-hover>tbody>.success:hover>td,.table-hover>tbody>.success:hover>th{background-color:#d0e9c6}.table>thead>tr>.danger,.table>tbody>tr>.danger,.table>tfoot>tr>.danger,.table>thead>.danger>td,.table>tbody>.danger>td,.table>tfoot>.danger>td,.table>thead>.danger>th,.table>tbody>.danger>th,.table>tfoot>.danger>th{background-color:#f2dede}.table-hover>tbody>tr>.danger:hover,.table-hover>tbody>.danger:hover>td,.table-hover>tbody>.danger:hover>th{background-color:#ebcccc}.table>thead>tr>.warning,.table>tbody>tr>.warning,.table>tfoot>tr>.warning,.table>thead>.warning>td,.table>tbody>.warning>td,.table>tfoot>.warning>td,.table>thead>.warning>th,.table>tbody>.warning>th,.table>tfoot>.warning>th{background-color:#fcf8e3}.table-hover>tbody>tr>.warning:hover,.table-hover>tbody>.warning:hover>td,.table-hover>tbody>.warning:hover>th{background-color:#faf2cc}@media(max-width:767px){.table-responsive{width:100%;margin-bottom:15px;overflow-x:scroll;overflow-y:hidden;border:1px solid #ddd;-ms-overflow-style:-ms-autohiding-scrollbar;-webkit-overflow-scrolling:touch}.table-responsive>.table{margin-bottom:0}.table-responsive>.table>thead>tr>th,.table-responsive>.table>tbody>tr>th,.table-responsive>.table>tfoot>tr>th,.table-responsive>.table>thead>tr>td,.table-responsive>.table>tbody>tr>td,.table-responsive>.table>tfoot>tr>td{white-space:nowrap}.table-responsive>.table-bordered{border:0}.table-responsive>.table-bordered>thead>tr>th:first-child,.table-responsive>.table-bordered>tbody>tr>th:first-child,.table-responsive>.table-bordered>tfoot>tr>th:first-child,.table-responsive>.table-bordered>thead>tr>td:first-child,.table-responsive>.table-bordered>tbody>tr>td:first-child,.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.table-responsive>.table-bordered>thead>tr>th:last-child,.table-responsive>.table-bordered>tbody>tr>th:last-child,.table-responsive>.table-bordered>tfoot>tr>th:last-child,.table-responsive>.table-bordered>thead>tr>td:last-child,.table-responsive>.table-bordered>tbody>tr>td:last-child,.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.table-responsive>.table-bordered>tbody>tr:last-child>th,.table-responsive>.table-bordered>tfoot>tr:last-child>th,.table-responsive>.table-bordered>tbody>tr:last-child>td,.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}}fieldset{padding:0;margin:0;border:0}legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:inherit;color:#555;border:0;border-bottom:1px solid #e5e5e5}label{display:inline-block;margin-bottom:5px;font-weight:bold}input[type="search"]{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}input[type="radio"],input[type="checkbox"]{margin:4px 0 0;margin-top:1px \9;line-height:normal}input[type="file"]{display:block}select[multiple],select[size]{height:auto}select optgroup{font-family:inherit;font-size:inherit;font-style:inherit}input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}input[type="number"]::-webkit-outer-spin-button,input[type="number"]::-webkit-inner-spin-button{height:auto}output{display:block;padding-top:9px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle}.form-control{display:block;width:100%;height:38px;padding:8px 12px;font-size:14px;line-height:1.428571429;color:#555;vertical-align:middle;background-color:#fff;background-image:none;border:1px solid #ccc;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);-webkit-transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s;transition:border-color ease-in-out .15s,box-shadow ease-in-out .15s}.form-control:focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 8px rgba(102,175,233,0.6)}.form-control:-moz-placeholder{color:#999}.form-control::-moz-placeholder{color:#999;opacity:1}.form-control:-ms-input-placeholder{color:#999}.form-control::-webkit-input-placeholder{color:#999}.form-control[disabled],.form-control[readonly],fieldset[disabled] .form-control{cursor:not-allowed;background-color:#eee}textarea.form-control{height:auto}.form-group{margin-bottom:15px}.radio,.checkbox{display:block;min-height:20px;padding-left:20px;margin-top:10px;margin-bottom:10px;vertical-align:middle}.radio label,.checkbox label{display:inline;margin-bottom:0;font-weight:normal;cursor:pointer}.radio input[type="radio"],.radio-inline input[type="radio"],.checkbox input[type="checkbox"],.checkbox-inline input[type="checkbox"]{float:left;margin-left:-20px}.radio+.radio,.checkbox+.checkbox{margin-top:-5px}.radio-inline,.checkbox-inline{display:inline-block;padding-left:20px;margin-bottom:0;font-weight:normal;vertical-align:middle;cursor:pointer}.radio-inline+.radio-inline,.checkbox-inline+.checkbox-inline{margin-top:0;margin-left:10px}input[type="radio"][disabled],input[type="checkbox"][disabled],.radio[disabled],.radio-inline[disabled],.checkbox[disabled],.checkbox-inline[disabled],fieldset[disabled] input[type="radio"],fieldset[disabled] input[type="checkbox"],fieldset[disabled] .radio,fieldset[disabled] .radio-inline,fieldset[disabled] .checkbox,fieldset[disabled] .checkbox-inline{cursor:not-allowed}.input-sm{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-sm{height:30px;line-height:30px}textarea.input-sm{height:auto}.input-lg{height:54px;padding:14px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-lg{height:54px;line-height:54px}textarea.input-lg{height:auto}.has-warning .help-block,.has-warning .control-label,.has-warning .radio,.has-warning .checkbox,.has-warning .radio-inline,.has-warning .checkbox-inline{color:#c09853}.has-warning .form-control{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-warning .form-control:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #dbc59e}.has-warning .input-group-addon{color:#c09853;background-color:#fcf8e3;border-color:#c09853}.has-error .help-block,.has-error .control-label,.has-error .radio,.has-error .checkbox,.has-error .radio-inline,.has-error .checkbox-inline{color:#b94a48}.has-error .form-control{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-error .form-control:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #d59392}.has-error .input-group-addon{color:#b94a48;background-color:#f2dede;border-color:#b94a48}.has-success .help-block,.has-success .control-label,.has-success .radio,.has-success .checkbox,.has-success .radio-inline,.has-success .checkbox-inline{color:#468847}.has-success .form-control{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075);box-shadow:inset 0 1px 1px rgba(0,0,0,0.075)}.has-success .form-control:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0,0,0,0.075),0 0 6px #7aba7b}.has-success .input-group-addon{color:#468847;background-color:#dff0d8;border-color:#468847}.form-control-static{margin-bottom:0}.help-block{display:block;margin-top:5px;margin-bottom:10px;color:#959595}@media(min-width:768px){.form-inline .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.form-inline .form-control{display:inline-block}.form-inline select.form-control{width:auto}.form-inline .radio,.form-inline .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:none;margin-left:0}}.form-horizontal .control-label,.form-horizontal .radio,.form-horizontal .checkbox,.form-horizontal .radio-inline,.form-horizontal .checkbox-inline{padding-top:9px;margin-top:0;margin-bottom:0}.form-horizontal .radio,.form-horizontal .checkbox{min-height:29px}.form-horizontal .form-group{margin-right:-15px;margin-left:-15px}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-group:before,.form-horizontal .form-group:after{display:table;content:" "}.form-horizontal .form-group:after{clear:both}.form-horizontal .form-control-static{padding-top:9px}@media(min-width:768px){.form-horizontal .control-label{text-align:right}}.btn{display:inline-block;padding:8px 12px;margin-bottom:0;font-size:14px;font-weight:normal;line-height:1.428571429;text-align:center;white-space:nowrap;vertical-align:middle;cursor:pointer;background-image:none;border:1px solid transparent;border-radius:4px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none}.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px}.btn:hover,.btn:focus{color:#555;text-decoration:none}.btn:active,.btn.active{background-image:none;outline:0;-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn.disabled,.btn[disabled],fieldset[disabled] .btn{pointer-events:none;cursor:not-allowed;opacity:.65;filter:alpha(opacity=65);-webkit-box-shadow:none;box-shadow:none}.btn-default{color:#555;background-color:#fff;border-color:rgba(0,0,0,0.1)}.btn-default:hover,.btn-default:focus,.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{color:#555;background-color:#ebebeb;border-color:rgba(0,0,0,0.1)}.btn-default:active,.btn-default.active,.open .dropdown-toggle.btn-default{background-image:none}.btn-default.disabled,.btn-default[disabled],fieldset[disabled] .btn-default,.btn-default.disabled:hover,.btn-default[disabled]:hover,fieldset[disabled] .btn-default:hover,.btn-default.disabled:focus,.btn-default[disabled]:focus,fieldset[disabled] .btn-default:focus,.btn-default.disabled:active,.btn-default[disabled]:active,fieldset[disabled] .btn-default:active,.btn-default.disabled.active,.btn-default[disabled].active,fieldset[disabled] .btn-default.active{background-color:#fff;border-color:rgba(0,0,0,0.1)}.btn-default .badge{color:#fff;background-color:#fff}.btn-primary{color:#fff;background-color:#2fa4e7;border-color:#2fa4e7}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#1990d5;border-color:#1684c2}.btn-primary:active,.btn-primary.active,.open .dropdown-toggle.btn-primary{background-image:none}.btn-primary.disabled,.btn-primary[disabled],fieldset[disabled] .btn-primary,.btn-primary.disabled:hover,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary:hover,.btn-primary.disabled:focus,.btn-primary[disabled]:focus,fieldset[disabled] .btn-primary:focus,.btn-primary.disabled:active,.btn-primary[disabled]:active,fieldset[disabled] .btn-primary:active,.btn-primary.disabled.active,.btn-primary[disabled].active,fieldset[disabled] .btn-primary.active{background-color:#2fa4e7;border-color:#2fa4e7}.btn-primary .badge{color:#2fa4e7;background-color:#fff}.btn-warning{color:#fff;background-color:#dd5600;border-color:#dd5600}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{color:#fff;background-color:#b44600;border-color:#a03e00}.btn-warning:active,.btn-warning.active,.open .dropdown-toggle.btn-warning{background-image:none}.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-warning,.btn-warning.disabled:hover,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning:hover,.btn-warning.disabled:focus,.btn-warning[disabled]:focus,fieldset[disabled] .btn-warning:focus,.btn-warning.disabled:active,.btn-warning[disabled]:active,fieldset[disabled] .btn-warning:active,.btn-warning.disabled.active,.btn-warning[disabled].active,fieldset[disabled] .btn-warning.active{background-color:#dd5600;border-color:#dd5600}.btn-warning .badge{color:#dd5600;background-color:#fff}.btn-danger{color:#fff;background-color:#c71c22;border-color:#c71c22}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{color:#fff;background-color:#a3171c;border-color:#911419}.btn-danger:active,.btn-danger.active,.open .dropdown-toggle.btn-danger{background-image:none}.btn-danger.disabled,.btn-danger[disabled],fieldset[disabled] .btn-danger,.btn-danger.disabled:hover,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger:hover,.btn-danger.disabled:focus,.btn-danger[disabled]:focus,fieldset[disabled] .btn-danger:focus,.btn-danger.disabled:active,.btn-danger[disabled]:active,fieldset[disabled] .btn-danger:active,.btn-danger.disabled.active,.btn-danger[disabled].active,fieldset[disabled] .btn-danger.active{background-color:#c71c22;border-color:#c71c22}.btn-danger .badge{color:#c71c22;background-color:#fff}.btn-success{color:#fff;background-color:#73a839;border-color:#73a839}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{color:#fff;background-color:#5e8a2f;border-color:#547a29}.btn-success:active,.btn-success.active,.open .dropdown-toggle.btn-success{background-image:none}.btn-success.disabled,.btn-success[disabled],fieldset[disabled] .btn-success,.btn-success.disabled:hover,.btn-success[disabled]:hover,fieldset[disabled] .btn-success:hover,.btn-success.disabled:focus,.btn-success[disabled]:focus,fieldset[disabled] .btn-success:focus,.btn-success.disabled:active,.btn-success[disabled]:active,fieldset[disabled] .btn-success:active,.btn-success.disabled.active,.btn-success[disabled].active,fieldset[disabled] .btn-success.active{background-color:#73a839;border-color:#73a839}.btn-success .badge{color:#73a839;background-color:#fff}.btn-info{color:#fff;background-color:#033c73;border-color:#033c73}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{color:#fff;background-color:#02274b;border-color:#011d37}.btn-info:active,.btn-info.active,.open .dropdown-toggle.btn-info{background-image:none}.btn-info.disabled,.btn-info[disabled],fieldset[disabled] .btn-info,.btn-info.disabled:hover,.btn-info[disabled]:hover,fieldset[disabled] .btn-info:hover,.btn-info.disabled:focus,.btn-info[disabled]:focus,fieldset[disabled] .btn-info:focus,.btn-info.disabled:active,.btn-info[disabled]:active,fieldset[disabled] .btn-info:active,.btn-info.disabled.active,.btn-info[disabled].active,fieldset[disabled] .btn-info.active{background-color:#033c73;border-color:#033c73}.btn-info .badge{color:#033c73;background-color:#fff}.btn-link{font-weight:normal;color:#2fa4e7;cursor:pointer;border-radius:0}.btn-link,.btn-link:active,.btn-link[disabled],fieldset[disabled] .btn-link{background-color:transparent;-webkit-box-shadow:none;box-shadow:none}.btn-link,.btn-link:hover,.btn-link:focus,.btn-link:active{border-color:transparent}.btn-link:hover,.btn-link:focus{color:#157ab5;text-decoration:underline;background-color:transparent}.btn-link[disabled]:hover,fieldset[disabled] .btn-link:hover,.btn-link[disabled]:focus,fieldset[disabled] .btn-link:focus{color:#999;text-decoration:none}.btn-lg{padding:14px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-sm{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-xs{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-block{display:block;width:100%;padding-right:0;padding-left:0}.btn-block+.btn-block{margin-top:5px}input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%}.fade{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.fade.in{opacity:1}.collapse{display:none}.collapse.in{display:block}.collapsing{position:relative;height:0;overflow:hidden;-webkit-transition:height .35s ease;transition:height .35s ease}@font-face{font-family:'Glyphicons Halflings';src:url('../fonts/glyphicons-halflings-regular.eot');src:url('../fonts/glyphicons-halflings-regular.eot?#iefix') format('embedded-opentype'),url('../fonts/glyphicons-halflings-regular.woff') format('woff'),url('../fonts/glyphicons-halflings-regular.ttf') format('truetype'),url('../fonts/glyphicons-halflings-regular.svg#glyphicons-halflingsregular') format('svg')}.glyphicon{position:relative;top:1px;display:inline-block;font-family:'Glyphicons Halflings';-webkit-font-smoothing:antialiased;font-style:normal;font-weight:normal;line-height:1;-moz-osx-font-smoothing:grayscale}.glyphicon:empty{width:1em}.glyphicon-asterisk:before{content:"\2a"}.glyphicon-plus:before{content:"\2b"}.glyphicon-euro:before{content:"\20ac"}.glyphicon-minus:before{content:"\2212"}.glyphicon-cloud:before{content:"\2601"}.glyphicon-envelope:before{content:"\2709"}.glyphicon-pencil:before{content:"\270f"}.glyphicon-glass:before{content:"\e001"}.glyphicon-music:before{content:"\e002"}.glyphicon-search:before{content:"\e003"}.glyphicon-heart:before{content:"\e005"}.glyphicon-star:before{content:"\e006"}.glyphicon-star-empty:before{content:"\e007"}.glyphicon-user:before{content:"\e008"}.glyphicon-film:before{content:"\e009"}.glyphicon-th-large:before{content:"\e010"}.glyphicon-th:before{content:"\e011"}.glyphicon-th-list:before{content:"\e012"}.glyphicon-ok:before{content:"\e013"}.glyphicon-remove:before{content:"\e014"}.glyphicon-zoom-in:before{content:"\e015"}.glyphicon-zoom-out:before{content:"\e016"}.glyphicon-off:before{content:"\e017"}.glyphicon-signal:before{content:"\e018"}.glyphicon-cog:before{content:"\e019"}.glyphicon-trash:before{content:"\e020"}.glyphicon-home:before{content:"\e021"}.glyphicon-file:before{content:"\e022"}.glyphicon-time:before{content:"\e023"}.glyphicon-road:before{content:"\e024"}.glyphicon-download-alt:before{content:"\e025"}.glyphicon-download:before{content:"\e026"}.glyphicon-upload:before{content:"\e027"}.glyphicon-inbox:before{content:"\e028"}.glyphicon-play-circle:before{content:"\e029"}.glyphicon-repeat:before{content:"\e030"}.glyphicon-refresh:before{content:"\e031"}.glyphicon-list-alt:before{content:"\e032"}.glyphicon-lock:before{content:"\e033"}.glyphicon-flag:before{content:"\e034"}.glyphicon-headphones:before{content:"\e035"}.glyphicon-volume-off:before{content:"\e036"}.glyphicon-volume-down:before{content:"\e037"}.glyphicon-volume-up:before{content:"\e038"}.glyphicon-qrcode:before{content:"\e039"}.glyphicon-barcode:before{content:"\e040"}.glyphicon-tag:before{content:"\e041"}.glyphicon-tags:before{content:"\e042"}.glyphicon-book:before{content:"\e043"}.glyphicon-bookmark:before{content:"\e044"}.glyphicon-print:before{content:"\e045"}.glyphicon-camera:before{content:"\e046"}.glyphicon-font:before{content:"\e047"}.glyphicon-bold:before{content:"\e048"}.glyphicon-italic:before{content:"\e049"}.glyphicon-text-height:before{content:"\e050"}.glyphicon-text-width:before{content:"\e051"}.glyphicon-align-left:before{content:"\e052"}.glyphicon-align-center:before{content:"\e053"}.glyphicon-align-right:before{content:"\e054"}.glyphicon-align-justify:before{content:"\e055"}.glyphicon-list:before{content:"\e056"}.glyphicon-indent-left:before{content:"\e057"}.glyphicon-indent-right:before{content:"\e058"}.glyphicon-facetime-video:before{content:"\e059"}.glyphicon-picture:before{content:"\e060"}.glyphicon-map-marker:before{content:"\e062"}.glyphicon-adjust:before{content:"\e063"}.glyphicon-tint:before{content:"\e064"}.glyphicon-edit:before{content:"\e065"}.glyphicon-share:before{content:"\e066"}.glyphicon-check:before{content:"\e067"}.glyphicon-move:before{content:"\e068"}.glyphicon-step-backward:before{content:"\e069"}.glyphicon-fast-backward:before{content:"\e070"}.glyphicon-backward:before{content:"\e071"}.glyphicon-play:before{content:"\e072"}.glyphicon-pause:before{content:"\e073"}.glyphicon-stop:before{content:"\e074"}.glyphicon-forward:before{content:"\e075"}.glyphicon-fast-forward:before{content:"\e076"}.glyphicon-step-forward:before{content:"\e077"}.glyphicon-eject:before{content:"\e078"}.glyphicon-chevron-left:before{content:"\e079"}.glyphicon-chevron-right:before{content:"\e080"}.glyphicon-plus-sign:before{content:"\e081"}.glyphicon-minus-sign:before{content:"\e082"}.glyphicon-remove-sign:before{content:"\e083"}.glyphicon-ok-sign:before{content:"\e084"}.glyphicon-question-sign:before{content:"\e085"}.glyphicon-info-sign:before{content:"\e086"}.glyphicon-screenshot:before{content:"\e087"}.glyphicon-remove-circle:before{content:"\e088"}.glyphicon-ok-circle:before{content:"\e089"}.glyphicon-ban-circle:before{content:"\e090"}.glyphicon-arrow-left:before{content:"\e091"}.glyphicon-arrow-right:before{content:"\e092"}.glyphicon-arrow-up:before{content:"\e093"}.glyphicon-arrow-down:before{content:"\e094"}.glyphicon-share-alt:before{content:"\e095"}.glyphicon-resize-full:before{content:"\e096"}.glyphicon-resize-small:before{content:"\e097"}.glyphicon-exclamation-sign:before{content:"\e101"}.glyphicon-gift:before{content:"\e102"}.glyphicon-leaf:before{content:"\e103"}.glyphicon-fire:before{content:"\e104"}.glyphicon-eye-open:before{content:"\e105"}.glyphicon-eye-close:before{content:"\e106"}.glyphicon-warning-sign:before{content:"\e107"}.glyphicon-plane:before{content:"\e108"}.glyphicon-calendar:before{content:"\e109"}.glyphicon-random:before{content:"\e110"}.glyphicon-comment:before{content:"\e111"}.glyphicon-magnet:before{content:"\e112"}.glyphicon-chevron-up:before{content:"\e113"}.glyphicon-chevron-down:before{content:"\e114"}.glyphicon-retweet:before{content:"\e115"}.glyphicon-shopping-cart:before{content:"\e116"}.glyphicon-folder-close:before{content:"\e117"}.glyphicon-folder-open:before{content:"\e118"}.glyphicon-resize-vertical:before{content:"\e119"}.glyphicon-resize-horizontal:before{content:"\e120"}.glyphicon-hdd:before{content:"\e121"}.glyphicon-bullhorn:before{content:"\e122"}.glyphicon-bell:before{content:"\e123"}.glyphicon-certificate:before{content:"\e124"}.glyphicon-thumbs-up:before{content:"\e125"}.glyphicon-thumbs-down:before{content:"\e126"}.glyphicon-hand-right:before{content:"\e127"}.glyphicon-hand-left:before{content:"\e128"}.glyphicon-hand-up:before{content:"\e129"}.glyphicon-hand-down:before{content:"\e130"}.glyphicon-circle-arrow-right:before{content:"\e131"}.glyphicon-circle-arrow-left:before{content:"\e132"}.glyphicon-circle-arrow-up:before{content:"\e133"}.glyphicon-circle-arrow-down:before{content:"\e134"}.glyphicon-globe:before{content:"\e135"}.glyphicon-wrench:before{content:"\e136"}.glyphicon-tasks:before{content:"\e137"}.glyphicon-filter:before{content:"\e138"}.glyphicon-briefcase:before{content:"\e139"}.glyphicon-fullscreen:before{content:"\e140"}.glyphicon-dashboard:before{content:"\e141"}.glyphicon-paperclip:before{content:"\e142"}.glyphicon-heart-empty:before{content:"\e143"}.glyphicon-link:before{content:"\e144"}.glyphicon-phone:before{content:"\e145"}.glyphicon-pushpin:before{content:"\e146"}.glyphicon-usd:before{content:"\e148"}.glyphicon-gbp:before{content:"\e149"}.glyphicon-sort:before{content:"\e150"}.glyphicon-sort-by-alphabet:before{content:"\e151"}.glyphicon-sort-by-alphabet-alt:before{content:"\e152"}.glyphicon-sort-by-order:before{content:"\e153"}.glyphicon-sort-by-order-alt:before{content:"\e154"}.glyphicon-sort-by-attributes:before{content:"\e155"}.glyphicon-sort-by-attributes-alt:before{content:"\e156"}.glyphicon-unchecked:before{content:"\e157"}.glyphicon-expand:before{content:"\e158"}.glyphicon-collapse-down:before{content:"\e159"}.glyphicon-collapse-up:before{content:"\e160"}.glyphicon-log-in:before{content:"\e161"}.glyphicon-flash:before{content:"\e162"}.glyphicon-log-out:before{content:"\e163"}.glyphicon-new-window:before{content:"\e164"}.glyphicon-record:before{content:"\e165"}.glyphicon-save:before{content:"\e166"}.glyphicon-open:before{content:"\e167"}.glyphicon-saved:before{content:"\e168"}.glyphicon-import:before{content:"\e169"}.glyphicon-export:before{content:"\e170"}.glyphicon-send:before{content:"\e171"}.glyphicon-floppy-disk:before{content:"\e172"}.glyphicon-floppy-saved:before{content:"\e173"}.glyphicon-floppy-remove:before{content:"\e174"}.glyphicon-floppy-save:before{content:"\e175"}.glyphicon-floppy-open:before{content:"\e176"}.glyphicon-credit-card:before{content:"\e177"}.glyphicon-transfer:before{content:"\e178"}.glyphicon-cutlery:before{content:"\e179"}.glyphicon-header:before{content:"\e180"}.glyphicon-compressed:before{content:"\e181"}.glyphicon-earphone:before{content:"\e182"}.glyphicon-phone-alt:before{content:"\e183"}.glyphicon-tower:before{content:"\e184"}.glyphicon-stats:before{content:"\e185"}.glyphicon-sd-video:before{content:"\e186"}.glyphicon-hd-video:before{content:"\e187"}.glyphicon-subtitles:before{content:"\e188"}.glyphicon-sound-stereo:before{content:"\e189"}.glyphicon-sound-dolby:before{content:"\e190"}.glyphicon-sound-5-1:before{content:"\e191"}.glyphicon-sound-6-1:before{content:"\e192"}.glyphicon-sound-7-1:before{content:"\e193"}.glyphicon-copyright-mark:before{content:"\e194"}.glyphicon-registration-mark:before{content:"\e195"}.glyphicon-cloud-download:before{content:"\e197"}.glyphicon-cloud-upload:before{content:"\e198"}.glyphicon-tree-conifer:before{content:"\e199"}.glyphicon-tree-deciduous:before{content:"\e200"}.caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}.dropdown{position:relative}.dropdown-toggle:focus{outline:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;list-style:none;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.15);border-radius:4px;-webkit-box-shadow:0 6px 12px rgba(0,0,0,0.175);box-shadow:0 6px 12px rgba(0,0,0,0.175);background-clip:padding-box}.dropdown-menu.pull-right{right:0;left:auto}.dropdown-menu .divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.428571429;color:#333;white-space:nowrap}.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus{color:#fff;text-decoration:none;background-color:#2fa4e7}.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#fff;text-decoration:none;background-color:#2fa4e7;outline:0}.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999}.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;cursor:not-allowed;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.open>.dropdown-menu{display:block}.open>a{outline:0}.dropdown-header{display:block;padding:3px 20px;font-size:12px;line-height:1.428571429;color:#999}.dropdown-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:990}.pull-right>.dropdown-menu{right:0;left:auto}.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid;content:""}.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px}@media(min-width:768px){.navbar-right .dropdown-menu{right:0;left:auto}}.btn-group,.btn-group-vertical{position:relative;display:inline-block;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;float:left}.btn-group>.btn:hover,.btn-group-vertical>.btn:hover,.btn-group>.btn:focus,.btn-group-vertical>.btn:focus,.btn-group>.btn:active,.btn-group-vertical>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn.active{z-index:2}.btn-group>.btn:focus,.btn-group-vertical>.btn:focus{outline:0}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group{margin-left:-1px}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar:before,.btn-toolbar:after{display:table;content:" "}.btn-toolbar:after{clear:both}.btn-toolbar .btn-group{float:left}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group,.btn-toolbar>.btn-group+.btn-group{margin-left:5px}.btn-group>.btn:not(:first-child):not(:last-child):not(.dropdown-toggle){border-radius:0}.btn-group>.btn:first-child{margin-left:0}.btn-group>.btn:first-child:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn:last-child:not(:first-child),.btn-group>.dropdown-toggle:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.btn-group>.btn-group{float:left}.btn-group>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group>.btn-group:first-child>.btn:last-child,.btn-group>.btn-group:first-child>.dropdown-toggle{border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:last-child>.btn:first-child{border-bottom-left-radius:0;border-top-left-radius:0}.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0}.btn-group-xs>.btn{padding:1px 5px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-sm>.btn{padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}.btn-group-lg>.btn{padding:14px 16px;font-size:18px;line-height:1.33;border-radius:6px}.btn-group>.btn+.dropdown-toggle{padding-right:8px;padding-left:8px}.btn-group>.btn-lg+.dropdown-toggle{padding-right:12px;padding-left:12px}.btn-group.open .dropdown-toggle{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,0.125);box-shadow:inset 0 3px 5px rgba(0,0,0,0.125)}.btn-group.open .dropdown-toggle.btn-link{-webkit-box-shadow:none;box-shadow:none}.btn .caret{margin-left:0}.btn-lg .caret{border-width:5px 5px 0;border-bottom-width:0}.dropup .btn-lg .caret{border-width:0 5px 5px}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group,.btn-group-vertical>.btn-group>.btn{display:block;float:none;width:100%;max-width:100%}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group:before,.btn-group-vertical>.btn-group:after{display:table;content:" "}.btn-group-vertical>.btn-group:after{clear:both}.btn-group-vertical>.btn-group>.btn{float:none}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.btn-group-vertical>.btn:not(:first-child):not(:last-child){border-radius:0}.btn-group-vertical>.btn:first-child:not(:last-child){border-top-right-radius:4px;border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn:last-child:not(:first-child){border-top-right-radius:0;border-bottom-left-radius:4px;border-top-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child):not(:last-child)>.btn{border-radius:0}.btn-group-vertical>.btn-group:first-child>.btn:last-child,.btn-group-vertical>.btn-group:first-child>.dropdown-toggle{border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:last-child>.btn:first-child{border-top-right-radius:0;border-top-left-radius:0}.btn-group-justified{display:table;width:100%;border-collapse:separate;table-layout:fixed}.btn-group-justified>.btn,.btn-group-justified>.btn-group{display:table-cell;float:none;width:1%}.btn-group-justified>.btn-group .btn{width:100%}[data-toggle="buttons"]>.btn>input[type="radio"],[data-toggle="buttons"]>.btn>input[type="checkbox"]{display:none}.input-group{position:relative;display:table;border-collapse:separate}.input-group[class*="col-"]{float:none;padding-right:0;padding-left:0}.input-group .form-control{width:100%;margin-bottom:0}.input-group-lg>.form-control,.input-group-lg>.input-group-addon,.input-group-lg>.input-group-btn>.btn{height:54px;padding:14px 16px;font-size:18px;line-height:1.33;border-radius:6px}select.input-group-lg>.form-control,select.input-group-lg>.input-group-addon,select.input-group-lg>.input-group-btn>.btn{height:54px;line-height:54px}textarea.input-group-lg>.form-control,textarea.input-group-lg>.input-group-addon,textarea.input-group-lg>.input-group-btn>.btn{height:auto}.input-group-sm>.form-control,.input-group-sm>.input-group-addon,.input-group-sm>.input-group-btn>.btn{height:30px;padding:5px 10px;font-size:12px;line-height:1.5;border-radius:3px}select.input-group-sm>.form-control,select.input-group-sm>.input-group-addon,select.input-group-sm>.input-group-btn>.btn{height:30px;line-height:30px}textarea.input-group-sm>.form-control,textarea.input-group-sm>.input-group-addon,textarea.input-group-sm>.input-group-btn>.btn{height:auto}.input-group-addon,.input-group-btn,.input-group .form-control{display:table-cell}.input-group-addon:not(:first-child):not(:last-child),.input-group-btn:not(:first-child):not(:last-child),.input-group .form-control:not(:first-child):not(:last-child){border-radius:0}.input-group-addon,.input-group-btn{width:1%;white-space:nowrap;vertical-align:middle}.input-group-addon{padding:8px 12px;font-size:14px;font-weight:normal;line-height:1;color:#555;text-align:center;background-color:#eee;border:1px solid #ccc;border-radius:4px}.input-group-addon.input-sm{padding:5px 10px;font-size:12px;border-radius:3px}.input-group-addon.input-lg{padding:14px 16px;font-size:18px;border-radius:6px}.input-group-addon input[type="radio"],.input-group-addon input[type="checkbox"]{margin-top:0}.input-group .form-control:first-child,.input-group-addon:first-child,.input-group-btn:first-child>.btn,.input-group-btn:first-child>.dropdown-toggle,.input-group-btn:last-child>.btn:not(:last-child):not(.dropdown-toggle){border-top-right-radius:0;border-bottom-right-radius:0}.input-group-addon:first-child{border-right:0}.input-group .form-control:last-child,.input-group-addon:last-child,.input-group-btn:last-child>.btn,.input-group-btn:last-child>.dropdown-toggle,.input-group-btn:first-child>.btn:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.input-group-addon:last-child{border-left:0}.input-group-btn{position:relative;white-space:nowrap}.input-group-btn:first-child>.btn{margin-right:-1px}.input-group-btn:last-child>.btn{margin-left:-1px}.input-group-btn>.btn{position:relative}.input-group-btn>.btn+.btn{margin-left:-4px}.input-group-btn>.btn:hover,.input-group-btn>.btn:active{z-index:2}.nav{padding-left:0;margin-bottom:0;list-style:none}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav:before,.nav:after{display:table;content:" "}.nav:after{clear:both}.nav>li{position:relative;display:block}.nav>li>a{position:relative;display:block;padding:10px 15px}.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eee}.nav>li.disabled>a{color:#999}.nav>li.disabled>a:hover,.nav>li.disabled>a:focus{color:#999;text-decoration:none;cursor:not-allowed;background-color:transparent}.nav .open>a,.nav .open>a:hover,.nav .open>a:focus{background-color:#eee;border-color:#2fa4e7}.nav .nav-divider{height:1px;margin:9px 0;overflow:hidden;background-color:#e5e5e5}.nav>li>a>img{max-width:none}.nav-tabs{border-bottom:1px solid #ddd}.nav-tabs>li{float:left;margin-bottom:-1px}.nav-tabs>li>a{margin-right:2px;line-height:1.428571429;border:1px solid transparent;border-radius:4px 4px 0 0}.nav-tabs>li>a:hover{border-color:#eee #eee #ddd}.nav-tabs>li.active>a,.nav-tabs>li.active>a:hover,.nav-tabs>li.active>a:focus{color:#555;cursor:default;background-color:#fff;border:1px solid #ddd;border-bottom-color:transparent}.nav-tabs.nav-justified{width:100%;border-bottom:0}.nav-tabs.nav-justified>li{float:none}.nav-tabs.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-tabs.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-tabs.nav-justified>li{display:table-cell;width:1%}.nav-tabs.nav-justified>li>a{margin-bottom:0}}.nav-tabs.nav-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs.nav-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs.nav-justified>.active>a,.nav-tabs.nav-justified>.active>a:hover,.nav-tabs.nav-justified>.active>a:focus{border-bottom-color:#fff}}.nav-pills>li{float:left}.nav-pills>li>a{border-radius:4px}.nav-pills>li+li{margin-left:2px}.nav-pills>li.active>a,.nav-pills>li.active>a:hover,.nav-pills>li.active>a:focus{color:#fff;background-color:#2fa4e7}.nav-stacked>li{float:none}.nav-stacked>li+li{margin-top:2px;margin-left:0}.nav-justified{width:100%}.nav-justified>li{float:none}.nav-justified>li>a{margin-bottom:5px;text-align:center}.nav-justified>.dropdown .dropdown-menu{top:auto;left:auto}@media(min-width:768px){.nav-justified>li{display:table-cell;width:1%}.nav-justified>li>a{margin-bottom:0}}.nav-tabs-justified{border-bottom:0}.nav-tabs-justified>li>a{margin-right:0;border-radius:4px}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border:1px solid #ddd}@media(min-width:768px){.nav-tabs-justified>li>a{border-bottom:1px solid #ddd;border-radius:4px 4px 0 0}.nav-tabs-justified>.active>a,.nav-tabs-justified>.active>a:hover,.nav-tabs-justified>.active>a:focus{border-bottom-color:#fff}}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-right-radius:0;border-top-left-radius:0}.navbar{position:relative;min-height:50px;margin-bottom:20px;border:1px solid transparent}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}.navbar:before,.navbar:after{display:table;content:" "}.navbar:after{clear:both}@media(min-width:768px){.navbar{border-radius:4px}}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}.navbar-header:before,.navbar-header:after{display:table;content:" "}.navbar-header:after{clear:both}@media(min-width:768px){.navbar-header{float:left}}.navbar-collapse{max-height:340px;padding-right:15px;padding-left:15px;overflow-x:visible;border-top:1px solid transparent;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1);-webkit-overflow-scrolling:touch}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse:before,.navbar-collapse:after{display:table;content:" "}.navbar-collapse:after{clear:both}.navbar-collapse.in{overflow-y:auto}@media(min-width:768px){.navbar-collapse{width:auto;border-top:0;box-shadow:none}.navbar-collapse.collapse{display:block!important;height:auto!important;padding-bottom:0;overflow:visible!important}.navbar-collapse.in{overflow-y:visible}.navbar-fixed-top .navbar-collapse,.navbar-static-top .navbar-collapse,.navbar-fixed-bottom .navbar-collapse{padding-right:0;padding-left:0}}.container>.navbar-header,.container>.navbar-collapse{margin-right:-15px;margin-left:-15px}@media(min-width:768px){.container>.navbar-header,.container>.navbar-collapse{margin-right:0;margin-left:0}}.navbar-static-top{z-index:1000;border-width:0 0 1px}@media(min-width:768px){.navbar-static-top{border-radius:0}}.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030}@media(min-width:768px){.navbar-fixed-top,.navbar-fixed-bottom{border-radius:0}}.navbar-fixed-top{top:0;border-width:0 0 1px}.navbar-fixed-bottom{bottom:0;margin-bottom:0;border-width:1px 0 0}.navbar-brand{float:left;padding:15px 15px;font-size:18px;line-height:20px}.navbar-brand:hover,.navbar-brand:focus{text-decoration:none}@media(min-width:768px){.navbar>.container .navbar-brand{margin-left:-15px}}.navbar-toggle{position:relative;float:right;padding:9px 10px;margin-top:8px;margin-right:15px;margin-bottom:8px;background-color:transparent;background-image:none;border:1px solid transparent;border-radius:4px}.navbar-toggle .icon-bar{display:block;width:22px;height:2px;border-radius:1px}.navbar-toggle .icon-bar+.icon-bar{margin-top:4px}@media(min-width:768px){.navbar-toggle{display:none}}.navbar-nav{margin:7.5px -15px}.navbar-nav>li>a{padding-top:10px;padding-bottom:10px;line-height:20px}@media(max-width:767px){.navbar-nav .open .dropdown-menu{position:static;float:none;width:auto;margin-top:0;background-color:transparent;border:0;box-shadow:none}.navbar-nav .open .dropdown-menu>li>a,.navbar-nav .open .dropdown-menu .dropdown-header{padding:5px 15px 5px 25px}.navbar-nav .open .dropdown-menu>li>a{line-height:20px}.navbar-nav .open .dropdown-menu>li>a:hover,.navbar-nav .open .dropdown-menu>li>a:focus{background-image:none}}@media(min-width:768px){.navbar-nav{float:left;margin:0}.navbar-nav>li{float:left}.navbar-nav>li>a{padding-top:15px;padding-bottom:15px}.navbar-nav.navbar-right:last-child{margin-right:-15px}}@media(min-width:768px){.navbar-left{float:left!important}.navbar-right{float:right!important}}.navbar-form{padding:10px 15px;margin-top:6px;margin-right:-15px;margin-bottom:6px;margin-left:-15px;border-top:1px solid transparent;border-bottom:1px solid transparent;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1);box-shadow:inset 0 1px 0 rgba(255,255,255,0.1),0 1px 0 rgba(255,255,255,0.1)}@media(min-width:768px){.navbar-form .form-group{display:inline-block;margin-bottom:0;vertical-align:middle}.navbar-form .form-control{display:inline-block}.navbar-form select.form-control{width:auto}.navbar-form .radio,.navbar-form .checkbox{display:inline-block;padding-left:0;margin-top:0;margin-bottom:0}.navbar-form .radio input[type="radio"],.navbar-form .checkbox input[type="checkbox"]{float:none;margin-left:0}}@media(max-width:767px){.navbar-form .form-group{margin-bottom:5px}}@media(min-width:768px){.navbar-form{width:auto;padding-top:0;padding-bottom:0;margin-right:0;margin-left:0;border:0;-webkit-box-shadow:none;box-shadow:none}.navbar-form.navbar-right:last-child{margin-right:-15px}}.navbar-nav>li>.dropdown-menu{margin-top:0;border-top-right-radius:0;border-top-left-radius:0}.navbar-fixed-bottom .navbar-nav>li>.dropdown-menu{border-bottom-right-radius:0;border-bottom-left-radius:0}.navbar-nav.pull-right>li>.dropdown-menu,.navbar-nav>li>.dropdown-menu.pull-right{right:0;left:auto}.navbar-btn{margin-top:6px;margin-bottom:6px}.navbar-btn.btn-sm{margin-top:10px;margin-bottom:10px}.navbar-btn.btn-xs{margin-top:14px;margin-bottom:14px}.navbar-text{margin-top:15px;margin-bottom:15px}@media(min-width:768px){.navbar-text{float:left;margin-right:15px;margin-left:15px}.navbar-text.navbar-right:last-child{margin-right:0}}.navbar-default{background-color:#2fa4e7;border-color:#1995dc}.navbar-default .navbar-brand{color:#fff}.navbar-default .navbar-brand:hover,.navbar-default .navbar-brand:focus{color:#fff;background-color:none}.navbar-default .navbar-text{color:#ddd}.navbar-default .navbar-nav>li>a{color:#fff}.navbar-default .navbar-nav>li>a:hover,.navbar-default .navbar-nav>li>a:focus{color:#fff;background-color:#178acc}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.active>a:hover,.navbar-default .navbar-nav>.active>a:focus{color:#fff;background-color:#178acc}.navbar-default .navbar-nav>.disabled>a,.navbar-default .navbar-nav>.disabled>a:hover,.navbar-default .navbar-nav>.disabled>a:focus{color:#ddd;background-color:transparent}.navbar-default .navbar-toggle{border-color:#178acc}.navbar-default .navbar-toggle:hover,.navbar-default .navbar-toggle:focus{background-color:#178acc}.navbar-default .navbar-toggle .icon-bar{background-color:#fff}.navbar-default .navbar-collapse,.navbar-default .navbar-form{border-color:#1995dc}.navbar-default .navbar-nav>.open>a,.navbar-default .navbar-nav>.open>a:hover,.navbar-default .navbar-nav>.open>a:focus{color:#fff;background-color:#178acc}@media(max-width:767px){.navbar-default .navbar-nav .open .dropdown-menu>li>a{color:#fff}.navbar-default .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:#178acc}.navbar-default .navbar-nav .open .dropdown-menu>.active>a,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#178acc}.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-default .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ddd;background-color:transparent}}.navbar-default .navbar-link{color:#fff}.navbar-default .navbar-link:hover{color:#fff}.navbar-inverse{background-color:#033c73;border-color:#022f5a}.navbar-inverse .navbar-brand{color:#fff}.navbar-inverse .navbar-brand:hover,.navbar-inverse .navbar-brand:focus{color:#fff;background-color:none}.navbar-inverse .navbar-text{color:#fff}.navbar-inverse .navbar-nav>li>a{color:#fff}.navbar-inverse .navbar-nav>li>a:hover,.navbar-inverse .navbar-nav>li>a:focus{color:#fff;background-color:#022f5a}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.active>a:hover,.navbar-inverse .navbar-nav>.active>a:focus{color:#fff;background-color:#022f5a}.navbar-inverse .navbar-nav>.disabled>a,.navbar-inverse .navbar-nav>.disabled>a:hover,.navbar-inverse .navbar-nav>.disabled>a:focus{color:#ccc;background-color:transparent}.navbar-inverse .navbar-toggle{border-color:#022f5a}.navbar-inverse .navbar-toggle:hover,.navbar-inverse .navbar-toggle:focus{background-color:#022f5a}.navbar-inverse .navbar-toggle .icon-bar{background-color:#fff}.navbar-inverse .navbar-collapse,.navbar-inverse .navbar-form{border-color:#022a50}.navbar-inverse .navbar-nav>.open>a,.navbar-inverse .navbar-nav>.open>a:hover,.navbar-inverse .navbar-nav>.open>a:focus{color:#fff;background-color:#022f5a}@media(max-width:767px){.navbar-inverse .navbar-nav .open .dropdown-menu>.dropdown-header{border-color:#022f5a}.navbar-inverse .navbar-nav .open .dropdown-menu .divider{background-color:#022f5a}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a{color:#fff}.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>li>a:focus{color:#fff;background-color:#022f5a}.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.active>a:focus{color:#fff;background-color:#022f5a}.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:hover,.navbar-inverse .navbar-nav .open .dropdown-menu>.disabled>a:focus{color:#ccc;background-color:transparent}}.navbar-inverse .navbar-link{color:#fff}.navbar-inverse .navbar-link:hover{color:#fff}.breadcrumb{padding:8px 15px;margin-bottom:20px;list-style:none;background-color:#f5f5f5;border-radius:4px}.breadcrumb>li{display:inline-block}.breadcrumb>li+li:before{padding:0 5px;color:#ccc;content:"/\00a0"}.breadcrumb>.active{color:#999}.pagination{display:inline-block;padding-left:0;margin:20px 0;border-radius:4px}.pagination>li{display:inline}.pagination>li>a,.pagination>li>span{position:relative;float:left;padding:8px 12px;margin-left:-1px;line-height:1.428571429;text-decoration:none;background-color:#fff;border:1px solid #ddd}.pagination>li:first-child>a,.pagination>li:first-child>span{margin-left:0;border-bottom-left-radius:4px;border-top-left-radius:4px}.pagination>li:last-child>a,.pagination>li:last-child>span{border-top-right-radius:4px;border-bottom-right-radius:4px}.pagination>li>a:hover,.pagination>li>span:hover,.pagination>li>a:focus,.pagination>li>span:focus{background-color:#eee}.pagination>.active>a,.pagination>.active>span,.pagination>.active>a:hover,.pagination>.active>span:hover,.pagination>.active>a:focus,.pagination>.active>span:focus{z-index:2;color:#999;cursor:default;background-color:#f5f5f5;border-color:#f5f5f5}.pagination>.disabled>span,.pagination>.disabled>span:hover,.pagination>.disabled>span:focus,.pagination>.disabled>a,.pagination>.disabled>a:hover,.pagination>.disabled>a:focus{color:#999;cursor:not-allowed;background-color:#fff;border-color:#ddd}.pagination-lg>li>a,.pagination-lg>li>span{padding:14px 16px;font-size:18px}.pagination-lg>li:first-child>a,.pagination-lg>li:first-child>span{border-bottom-left-radius:6px;border-top-left-radius:6px}.pagination-lg>li:last-child>a,.pagination-lg>li:last-child>span{border-top-right-radius:6px;border-bottom-right-radius:6px}.pagination-sm>li>a,.pagination-sm>li>span{padding:5px 10px;font-size:12px}.pagination-sm>li:first-child>a,.pagination-sm>li:first-child>span{border-bottom-left-radius:3px;border-top-left-radius:3px}.pagination-sm>li:last-child>a,.pagination-sm>li:last-child>span{border-top-right-radius:3px;border-bottom-right-radius:3px}.pager{padding-left:0;margin:20px 0;text-align:center;list-style:none}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager:before,.pager:after{display:table;content:" "}.pager:after{clear:both}.pager li{display:inline}.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;border-radius:15px}.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#eee}.pager .next>a,.pager .next>span{float:right}.pager .previous>a,.pager .previous>span{float:left}.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999;cursor:not-allowed;background-color:#fff}.label{display:inline;padding:.2em .6em .3em;font-size:75%;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:.25em}.label[href]:hover,.label[href]:focus{color:#fff;text-decoration:none;cursor:pointer}.label:empty{display:none}.btn .label{position:relative;top:-1px}.label-default{background-color:#999}.label-default[href]:hover,.label-default[href]:focus{background-color:#808080}.label-primary{background-color:#2fa4e7}.label-primary[href]:hover,.label-primary[href]:focus{background-color:#178acc}.label-success{background-color:#73a839}.label-success[href]:hover,.label-success[href]:focus{background-color:#59822c}.label-info{background-color:#033c73}.label-info[href]:hover,.label-info[href]:focus{background-color:#022241}.label-warning{background-color:#dd5600}.label-warning[href]:hover,.label-warning[href]:focus{background-color:#aa4200}.label-danger{background-color:#c71c22}.label-danger[href]:hover,.label-danger[href]:focus{background-color:#9a161a}.badge{display:inline-block;min-width:10px;padding:3px 7px;font-size:12px;font-weight:bold;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline;background-color:#999;border-radius:10px}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}a.badge:hover,a.badge:focus{color:#fff;text-decoration:none;cursor:pointer}a.list-group-item.active>.badge,.nav-pills>.active>a>.badge{color:#2fa4e7;background-color:#fff}.nav-pills>li>a>.badge{margin-left:3px}.jumbotron{padding:30px;margin-bottom:30px;font-size:21px;font-weight:200;line-height:2.1428571435;color:inherit;background-color:#eee}.jumbotron h1,.jumbotron .h1{line-height:1;color:inherit}.jumbotron p{line-height:1.4}.container .jumbotron{border-radius:6px}.jumbotron .container{max-width:100%}@media screen and (min-width:768px){.jumbotron{padding-top:48px;padding-bottom:48px}.container .jumbotron{padding-right:60px;padding-left:60px}.jumbotron h1,.jumbotron .h1{font-size:63px}}.thumbnail{display:block;padding:4px;margin-bottom:20px;line-height:1.428571429;background-color:#fff;border:1px solid #ddd;border-radius:4px;-webkit-transition:all .2s ease-in-out;transition:all .2s ease-in-out}.thumbnail>img,.thumbnail a>img{display:block;height:auto;max-width:100%;margin-right:auto;margin-left:auto}a.thumbnail:hover,a.thumbnail:focus,a.thumbnail.active{border-color:#2fa4e7}.thumbnail .caption{padding:9px;color:#555}.alert{padding:15px;margin-bottom:20px;border:1px solid transparent;border-radius:4px}.alert h4{margin-top:0;color:inherit}.alert .alert-link{font-weight:bold}.alert>p,.alert>ul{margin-bottom:0}.alert>p+p{margin-top:5px}.alert-dismissable{padding-right:35px}.alert-dismissable .close{position:relative;top:-2px;right:-21px;color:inherit}.alert-success{color:#468847;background-color:#dff0d8;border-color:#d6e9c6}.alert-success hr{border-top-color:#c9e2b3}.alert-success .alert-link{color:#356635}.alert-info{color:#3a87ad;background-color:#d9edf7;border-color:#bce8f1}.alert-info hr{border-top-color:#a6e1ec}.alert-info .alert-link{color:#2d6987}.alert-warning{color:#c09853;background-color:#fcf8e3;border-color:#fbeed5}.alert-warning hr{border-top-color:#f8e5be}.alert-warning .alert-link{color:#a47e3c}.alert-danger{color:#b94a48;background-color:#f2dede;border-color:#eed3d7}.alert-danger hr{border-top-color:#e6c1c7}.alert-danger .alert-link{color:#953b39}@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}@keyframes progress-bar-stripes{from{background-position:40px 0}to{background-position:0 0}}.progress{height:20px;margin-bottom:20px;overflow:hidden;background-color:#f5f5f5;border-radius:4px;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.1);box-shadow:inset 0 1px 2px rgba(0,0,0,0.1)}.progress-bar{float:left;width:0;height:100%;font-size:12px;line-height:20px;color:#fff;text-align:center;background-color:#2fa4e7;-webkit-box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);box-shadow:inset 0 -1px 0 rgba(0,0,0,0.15);-webkit-transition:width .6s ease;transition:width .6s ease}.progress-striped .progress-bar{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-size:40px 40px}.progress.active .progress-bar{-webkit-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite}.progress-bar-success{background-color:#73a839}.progress-striped .progress-bar-success{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-info{background-color:#033c73}.progress-striped .progress-bar-info{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-warning{background-color:#dd5600}.progress-striped .progress-bar-warning{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.progress-bar-danger{background-color:#c71c22}.progress-striped .progress-bar-danger{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,0.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,0.15) 50%,rgba(255,255,255,0.15) 75%,transparent 75%,transparent)}.media,.media-body{overflow:hidden;zoom:1}.media,.media .media{margin-top:15px}.media:first-child{margin-top:0}.media-object{display:block}.media-heading{margin:0 0 5px}.media>.pull-left{margin-right:10px}.media>.pull-right{margin-left:10px}.media-list{padding-left:0;list-style:none}.list-group{padding-left:0;margin-bottom:20px}.list-group-item{position:relative;display:block;padding:10px 15px;margin-bottom:-1px;background-color:#fff;border:1px solid #ddd}.list-group-item:first-child{border-top-right-radius:4px;border-top-left-radius:4px}.list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:4px;border-bottom-left-radius:4px}.list-group-item>.badge{float:right}.list-group-item>.badge+.badge{margin-right:5px}a.list-group-item{color:#555}a.list-group-item .list-group-item-heading{color:#333}a.list-group-item:hover,a.list-group-item:focus{text-decoration:none;background-color:#f5f5f5}a.list-group-item.active,a.list-group-item.active:hover,a.list-group-item.active:focus{z-index:2;color:#fff;background-color:#2fa4e7;border-color:#2fa4e7}a.list-group-item.active .list-group-item-heading,a.list-group-item.active:hover .list-group-item-heading,a.list-group-item.active:focus .list-group-item-heading{color:inherit}a.list-group-item.active .list-group-item-text,a.list-group-item.active:hover .list-group-item-text,a.list-group-item.active:focus .list-group-item-text{color:#e6f4fc}.list-group-item-heading{margin-top:0;margin-bottom:5px}.list-group-item-text{margin-bottom:0;line-height:1.3}.panel{margin-bottom:20px;background-color:#fff;border:1px solid transparent;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.05);box-shadow:0 1px 1px rgba(0,0,0,0.05)}.panel-body{padding:15px}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel-body:before,.panel-body:after{display:table;content:" "}.panel-body:after{clear:both}.panel>.list-group{margin-bottom:0}.panel>.list-group .list-group-item{border-width:1px 0}.panel>.list-group .list-group-item:first-child{border-top-right-radius:0;border-top-left-radius:0}.panel>.list-group .list-group-item:last-child{border-bottom:0}.panel-heading+.list-group .list-group-item:first-child{border-top-width:0}.panel>.table,.panel>.table-responsive>.table{margin-bottom:0}.panel>.panel-body+.table,.panel>.panel-body+.table-responsive{border-top:1px solid #ddd}.panel>.table>tbody:first-child th,.panel>.table>tbody:first-child td{border-top:0}.panel>.table-bordered,.panel>.table-responsive>.table-bordered{border:0}.panel>.table-bordered>thead>tr>th:first-child,.panel>.table-responsive>.table-bordered>thead>tr>th:first-child,.panel>.table-bordered>tbody>tr>th:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:first-child,.panel>.table-bordered>tfoot>tr>th:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:first-child,.panel>.table-bordered>thead>tr>td:first-child,.panel>.table-responsive>.table-bordered>thead>tr>td:first-child,.panel>.table-bordered>tbody>tr>td:first-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:first-child,.panel>.table-bordered>tfoot>tr>td:first-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:first-child{border-left:0}.panel>.table-bordered>thead>tr>th:last-child,.panel>.table-responsive>.table-bordered>thead>tr>th:last-child,.panel>.table-bordered>tbody>tr>th:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>th:last-child,.panel>.table-bordered>tfoot>tr>th:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>th:last-child,.panel>.table-bordered>thead>tr>td:last-child,.panel>.table-responsive>.table-bordered>thead>tr>td:last-child,.panel>.table-bordered>tbody>tr>td:last-child,.panel>.table-responsive>.table-bordered>tbody>tr>td:last-child,.panel>.table-bordered>tfoot>tr>td:last-child,.panel>.table-responsive>.table-bordered>tfoot>tr>td:last-child{border-right:0}.panel>.table-bordered>thead>tr:last-child>th,.panel>.table-responsive>.table-bordered>thead>tr:last-child>th,.panel>.table-bordered>tbody>tr:last-child>th,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>th,.panel>.table-bordered>tfoot>tr:last-child>th,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>th,.panel>.table-bordered>thead>tr:last-child>td,.panel>.table-responsive>.table-bordered>thead>tr:last-child>td,.panel>.table-bordered>tbody>tr:last-child>td,.panel>.table-responsive>.table-bordered>tbody>tr:last-child>td,.panel>.table-bordered>tfoot>tr:last-child>td,.panel>.table-responsive>.table-bordered>tfoot>tr:last-child>td{border-bottom:0}.panel>.table-responsive{margin-bottom:0;border:0}.panel-heading{padding:10px 15px;border-bottom:1px solid transparent;border-top-right-radius:3px;border-top-left-radius:3px}.panel-heading>.dropdown .dropdown-toggle{color:inherit}.panel-title{margin-top:0;margin-bottom:0;font-size:16px;color:inherit}.panel-title>a{color:inherit}.panel-footer{padding:10px 15px;background-color:#f5f5f5;border-top:1px solid #ddd;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.panel-group .panel{margin-bottom:0;overflow:hidden;border-radius:4px}.panel-group .panel+.panel{margin-top:5px}.panel-group .panel-heading{border-bottom:0}.panel-group .panel-heading+.panel-collapse .panel-body{border-top:1px solid #ddd}.panel-group .panel-footer{border-top:0}.panel-group .panel-footer+.panel-collapse .panel-body{border-bottom:1px solid #ddd}.panel-default{border-color:#ddd}.panel-default>.panel-heading{color:#555;background-color:#f5f5f5;border-color:#ddd}.panel-default>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-default>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-primary{border-color:#ddd}.panel-primary>.panel-heading{color:#fff;background-color:#2fa4e7;border-color:#ddd}.panel-primary>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-primary>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-success{border-color:#ddd}.panel-success>.panel-heading{color:#468847;background-color:#73a839;border-color:#ddd}.panel-success>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-success>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-warning{border-color:#ddd}.panel-warning>.panel-heading{color:#c09853;background-color:#dd5600;border-color:#ddd}.panel-warning>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-warning>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-danger{border-color:#ddd}.panel-danger>.panel-heading{color:#b94a48;background-color:#c71c22;border-color:#ddd}.panel-danger>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-danger>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.panel-info{border-color:#ddd}.panel-info>.panel-heading{color:#3a87ad;background-color:#033c73;border-color:#ddd}.panel-info>.panel-heading+.panel-collapse .panel-body{border-top-color:#ddd}.panel-info>.panel-footer+.panel-collapse .panel-body{border-bottom-color:#ddd}.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,0.05);box-shadow:inset 0 1px 1px rgba(0,0,0,0.05)}.well blockquote{border-color:#ddd;border-color:rgba(0,0,0,0.15)}.well-lg{padding:24px;border-radius:6px}.well-sm{padding:9px;border-radius:3px}.close{float:right;font-size:21px;font-weight:bold;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.2;filter:alpha(opacity=20)}.close:hover,.close:focus{color:#000;text-decoration:none;cursor:pointer;opacity:.5;filter:alpha(opacity=50)}button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none}.modal-open{overflow:hidden}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;display:none;overflow:auto;overflow-y:scroll}.modal.fade .modal-dialog{-webkit-transform:translate(0,-25%);-ms-transform:translate(0,-25%);transform:translate(0,-25%);-webkit-transition:-webkit-transform .3s ease-out;-moz-transition:-moz-transform .3s ease-out;-o-transition:-o-transform .3s ease-out;transition:transform .3s ease-out}.modal.in .modal-dialog{-webkit-transform:translate(0,0);-ms-transform:translate(0,0);transform:translate(0,0)}.modal-dialog{position:relative;z-index:1050;width:auto;margin:10px}.modal-content{position:relative;background-color:#fff;border:1px solid #999;border:1px solid rgba(0,0,0,0.2);border-radius:6px;outline:0;-webkit-box-shadow:0 3px 9px rgba(0,0,0,0.5);box-shadow:0 3px 9px rgba(0,0,0,0.5);background-clip:padding-box}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000}.modal-backdrop.fade{opacity:0;filter:alpha(opacity=0)}.modal-backdrop.in{opacity:.5;filter:alpha(opacity=50)}.modal-header{min-height:16.428571429px;padding:15px;border-bottom:1px solid #e5e5e5}.modal-header .close{margin-top:-2px}.modal-title{margin:0;line-height:1.428571429}.modal-body{position:relative;padding:20px}.modal-footer{padding:19px 20px 20px;margin-top:15px;text-align:right;border-top:1px solid #e5e5e5}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer:before,.modal-footer:after{display:table;content:" "}.modal-footer:after{clear:both}.modal-footer .btn+.btn{margin-bottom:0;margin-left:5px}.modal-footer .btn-group .btn+.btn{margin-left:-1px}.modal-footer .btn-block+.btn-block{margin-left:0}@media screen and (min-width:768px){.modal-dialog{width:600px;margin:30px auto}.modal-content{-webkit-box-shadow:0 5px 15px rgba(0,0,0,0.5);box-shadow:0 5px 15px rgba(0,0,0,0.5)}}.tooltip{position:absolute;z-index:1030;display:block;font-size:12px;line-height:1.4;opacity:0;filter:alpha(opacity=0);visibility:visible}.tooltip.in{opacity:.9;filter:alpha(opacity=90)}.tooltip.top{padding:5px 0;margin-top:-3px}.tooltip.right{padding:0 5px;margin-left:3px}.tooltip.bottom{padding:5px 0;margin-top:3px}.tooltip.left{padding:0 5px;margin-left:-3px}.tooltip-inner{max-width:200px;padding:3px 8px;color:#fff;text-align:center;text-decoration:none;background-color:rgba(0,0,0,0.9);border-radius:4px}.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid}.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-top-color:rgba(0,0,0,0.9);border-width:5px 5px 0}.tooltip.top-left .tooltip-arrow{bottom:0;left:5px;border-top-color:rgba(0,0,0,0.9);border-width:5px 5px 0}.tooltip.top-right .tooltip-arrow{right:5px;bottom:0;border-top-color:rgba(0,0,0,0.9);border-width:5px 5px 0}.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-right-color:rgba(0,0,0,0.9);border-width:5px 5px 5px 0}.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-left-color:rgba(0,0,0,0.9);border-width:5px 0 5px 5px}.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-bottom-color:rgba(0,0,0,0.9);border-width:0 5px 5px}.tooltip.bottom-left .tooltip-arrow{top:0;left:5px;border-bottom-color:rgba(0,0,0,0.9);border-width:0 5px 5px}.tooltip.bottom-right .tooltip-arrow{top:0;right:5px;border-bottom-color:rgba(0,0,0,0.9);border-width:0 5px 5px}.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;white-space:normal;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0,0,0,0.2);border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0,0,0,0.2);box-shadow:0 5px 10px rgba(0,0,0,0.2);background-clip:padding-box}.popover.top{margin-top:-10px}.popover.right{margin-left:10px}.popover.bottom{margin-top:10px}.popover.left{margin-left:-10px}.popover-title{padding:8px 14px;margin:0;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-radius:5px 5px 0 0}.popover-content{padding:9px 14px}.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.popover .arrow{border-width:11px}.popover .arrow:after{border-width:10px;content:""}.popover.top .arrow{bottom:-11px;left:50%;margin-left:-11px;border-top-color:#999;border-top-color:rgba(0,0,0,0.25);border-bottom-width:0}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-top-color:#fff;border-bottom-width:0;content:" "}.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-right-color:#999;border-right-color:rgba(0,0,0,0.25);border-left-width:0}.popover.right .arrow:after{bottom:-10px;left:1px;border-right-color:#fff;border-left-width:0;content:" "}.popover.bottom .arrow{top:-11px;left:50%;margin-left:-11px;border-bottom-color:#999;border-bottom-color:rgba(0,0,0,0.25);border-top-width:0}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-bottom-color:#fff;border-top-width:0;content:" "}.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-left-color:#999;border-left-color:rgba(0,0,0,0.25);border-right-width:0}.popover.left .arrow:after{right:1px;bottom:-10px;border-left-color:#fff;border-right-width:0;content:" "}.carousel{position:relative}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner>.item{position:relative;display:none;-webkit-transition:.6s ease-in-out left;transition:.6s ease-in-out left}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;height:auto;max-width:100%;line-height:1}.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block}.carousel-inner>.active{left:0}.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%}.carousel-inner>.next{left:100%}.carousel-inner>.prev{left:-100%}.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0}.carousel-inner>.active.left{left:-100%}.carousel-inner>.active.right{left:100%}.carousel-control{position:absolute;top:0;bottom:0;left:0;width:15%;font-size:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6);opacity:.5;filter:alpha(opacity=50)}.carousel-control.left{background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.5) 0),color-stop(rgba(0,0,0,0.0001) 100%));background-image:linear-gradient(to right,rgba(0,0,0,0.5) 0,rgba(0,0,0,0.0001) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#80000000',endColorstr='#00000000',GradientType=1)}.carousel-control.right{right:0;left:auto;background-image:-webkit-linear-gradient(left,color-stop(rgba(0,0,0,0.0001) 0),color-stop(rgba(0,0,0,0.5) 100%));background-image:linear-gradient(to right,rgba(0,0,0,0.0001) 0,rgba(0,0,0,0.5) 100%);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#00000000',endColorstr='#80000000',GradientType=1)}.carousel-control:hover,.carousel-control:focus{color:#fff;text-decoration:none;outline:0;opacity:.9;filter:alpha(opacity=90)}.carousel-control .icon-prev,.carousel-control .icon-next,.carousel-control .glyphicon-chevron-left,.carousel-control .glyphicon-chevron-right{position:absolute;top:50%;z-index:5;display:inline-block}.carousel-control .icon-prev,.carousel-control .glyphicon-chevron-left{left:50%}.carousel-control .icon-next,.carousel-control .glyphicon-chevron-right{right:50%}.carousel-control .icon-prev,.carousel-control .icon-next{width:20px;height:20px;margin-top:-10px;margin-left:-10px;font-family:serif}.carousel-control .icon-prev:before{content:'\2039'}.carousel-control .icon-next:before{content:'\203a'}.carousel-indicators{position:absolute;bottom:10px;left:50%;z-index:15;width:60%;padding-left:0;margin-left:-30%;text-align:center;list-style:none}.carousel-indicators li{display:inline-block;width:10px;height:10px;margin:1px;text-indent:-999px;cursor:pointer;background-color:#000 \9;background-color:rgba(0,0,0,0);border:1px solid #fff;border-radius:10px}.carousel-indicators .active{width:12px;height:12px;margin:0;background-color:#fff}.carousel-caption{position:absolute;right:15%;bottom:20px;left:15%;z-index:10;padding-top:20px;padding-bottom:20px;color:#fff;text-align:center;text-shadow:0 1px 2px rgba(0,0,0,0.6)}.carousel-caption .btn{text-shadow:none}@media screen and (min-width:768px){.carousel-control .glyphicons-chevron-left,.carousel-control .glyphicons-chevron-right,.carousel-control .icon-prev,.carousel-control .icon-next{width:30px;height:30px;margin-top:-15px;margin-left:-15px;font-size:30px}.carousel-caption{right:20%;left:20%;padding-bottom:30px}.carousel-indicators{bottom:20px}}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed}@-ms-viewport{width:device-width}.visible-xs,tr.visible-xs,th.visible-xs,td.visible-xs{display:none!important}@media(max-width:767px){.visible-xs{display:block!important}table.visible-xs{display:table}tr.visible-xs{display:table-row!important}th.visible-xs,td.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-xs.visible-sm{display:block!important}table.visible-xs.visible-sm{display:table}tr.visible-xs.visible-sm{display:table-row!important}th.visible-xs.visible-sm,td.visible-xs.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-xs.visible-md{display:block!important}table.visible-xs.visible-md{display:table}tr.visible-xs.visible-md{display:table-row!important}th.visible-xs.visible-md,td.visible-xs.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-xs.visible-lg{display:block!important}table.visible-xs.visible-lg{display:table}tr.visible-xs.visible-lg{display:table-row!important}th.visible-xs.visible-lg,td.visible-xs.visible-lg{display:table-cell!important}}.visible-sm,tr.visible-sm,th.visible-sm,td.visible-sm{display:none!important}@media(max-width:767px){.visible-sm.visible-xs{display:block!important}table.visible-sm.visible-xs{display:table}tr.visible-sm.visible-xs{display:table-row!important}th.visible-sm.visible-xs,td.visible-sm.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-sm{display:block!important}table.visible-sm{display:table}tr.visible-sm{display:table-row!important}th.visible-sm,td.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-sm.visible-md{display:block!important}table.visible-sm.visible-md{display:table}tr.visible-sm.visible-md{display:table-row!important}th.visible-sm.visible-md,td.visible-sm.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-sm.visible-lg{display:block!important}table.visible-sm.visible-lg{display:table}tr.visible-sm.visible-lg{display:table-row!important}th.visible-sm.visible-lg,td.visible-sm.visible-lg{display:table-cell!important}}.visible-md,tr.visible-md,th.visible-md,td.visible-md{display:none!important}@media(max-width:767px){.visible-md.visible-xs{display:block!important}table.visible-md.visible-xs{display:table}tr.visible-md.visible-xs{display:table-row!important}th.visible-md.visible-xs,td.visible-md.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-md.visible-sm{display:block!important}table.visible-md.visible-sm{display:table}tr.visible-md.visible-sm{display:table-row!important}th.visible-md.visible-sm,td.visible-md.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-md{display:block!important}table.visible-md{display:table}tr.visible-md{display:table-row!important}th.visible-md,td.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-md.visible-lg{display:block!important}table.visible-md.visible-lg{display:table}tr.visible-md.visible-lg{display:table-row!important}th.visible-md.visible-lg,td.visible-md.visible-lg{display:table-cell!important}}.visible-lg,tr.visible-lg,th.visible-lg,td.visible-lg{display:none!important}@media(max-width:767px){.visible-lg.visible-xs{display:block!important}table.visible-lg.visible-xs{display:table}tr.visible-lg.visible-xs{display:table-row!important}th.visible-lg.visible-xs,td.visible-lg.visible-xs{display:table-cell!important}}@media(min-width:768px) and (max-width:991px){.visible-lg.visible-sm{display:block!important}table.visible-lg.visible-sm{display:table}tr.visible-lg.visible-sm{display:table-row!important}th.visible-lg.visible-sm,td.visible-lg.visible-sm{display:table-cell!important}}@media(min-width:992px) and (max-width:1199px){.visible-lg.visible-md{display:block!important}table.visible-lg.visible-md{display:table}tr.visible-lg.visible-md{display:table-row!important}th.visible-lg.visible-md,td.visible-lg.visible-md{display:table-cell!important}}@media(min-width:1200px){.visible-lg{display:block!important}table.visible-lg{display:table}tr.visible-lg{display:table-row!important}th.visible-lg,td.visible-lg{display:table-cell!important}}.hidden-xs{display:block!important}table.hidden-xs{display:table}tr.hidden-xs{display:table-row!important}th.hidden-xs,td.hidden-xs{display:table-cell!important}@media(max-width:767px){.hidden-xs,tr.hidden-xs,th.hidden-xs,td.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-xs.hidden-sm,tr.hidden-xs.hidden-sm,th.hidden-xs.hidden-sm,td.hidden-xs.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-xs.hidden-md,tr.hidden-xs.hidden-md,th.hidden-xs.hidden-md,td.hidden-xs.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-xs.hidden-lg,tr.hidden-xs.hidden-lg,th.hidden-xs.hidden-lg,td.hidden-xs.hidden-lg{display:none!important}}.hidden-sm{display:block!important}table.hidden-sm{display:table}tr.hidden-sm{display:table-row!important}th.hidden-sm,td.hidden-sm{display:table-cell!important}@media(max-width:767px){.hidden-sm.hidden-xs,tr.hidden-sm.hidden-xs,th.hidden-sm.hidden-xs,td.hidden-sm.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-sm,tr.hidden-sm,th.hidden-sm,td.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-sm.hidden-md,tr.hidden-sm.hidden-md,th.hidden-sm.hidden-md,td.hidden-sm.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-sm.hidden-lg,tr.hidden-sm.hidden-lg,th.hidden-sm.hidden-lg,td.hidden-sm.hidden-lg{display:none!important}}.hidden-md{display:block!important}table.hidden-md{display:table}tr.hidden-md{display:table-row!important}th.hidden-md,td.hidden-md{display:table-cell!important}@media(max-width:767px){.hidden-md.hidden-xs,tr.hidden-md.hidden-xs,th.hidden-md.hidden-xs,td.hidden-md.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-md.hidden-sm,tr.hidden-md.hidden-sm,th.hidden-md.hidden-sm,td.hidden-md.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-md,tr.hidden-md,th.hidden-md,td.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-md.hidden-lg,tr.hidden-md.hidden-lg,th.hidden-md.hidden-lg,td.hidden-md.hidden-lg{display:none!important}}.hidden-lg{display:block!important}table.hidden-lg{display:table}tr.hidden-lg{display:table-row!important}th.hidden-lg,td.hidden-lg{display:table-cell!important}@media(max-width:767px){.hidden-lg.hidden-xs,tr.hidden-lg.hidden-xs,th.hidden-lg.hidden-xs,td.hidden-lg.hidden-xs{display:none!important}}@media(min-width:768px) and (max-width:991px){.hidden-lg.hidden-sm,tr.hidden-lg.hidden-sm,th.hidden-lg.hidden-sm,td.hidden-lg.hidden-sm{display:none!important}}@media(min-width:992px) and (max-width:1199px){.hidden-lg.hidden-md,tr.hidden-lg.hidden-md,th.hidden-lg.hidden-md,td.hidden-lg.hidden-md{display:none!important}}@media(min-width:1200px){.hidden-lg,tr.hidden-lg,th.hidden-lg,td.hidden-lg{display:none!important}}.visible-print,tr.visible-print,th.visible-print,td.visible-print{display:none!important}@media print{.visible-print{display:block!important}table.visible-print{display:table}tr.visible-print{display:table-row!important}th.visible-print,td.visible-print{display:table-cell!important}.hidden-print,tr.hidden-print,th.hidden-print,td.hidden-print{display:none!important}}.navbar{background-image:-webkit-linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5);background-image:linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5);background-repeat:no-repeat;border-bottom:1px solid #178acc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff54b4eb',endColorstr='#ff1d9ce5',GradientType=0);filter:none;-webkit-box-shadow:0 1px 10px rgba(0,0,0,0.1);box-shadow:0 1px 10px rgba(0,0,0,0.1)}.navbar .navbar-nav>li>a,.navbar-brand{text-shadow:0 1px 0 rgba(0,0,0,0.1)}.navbar-inverse{background-image:-webkit-linear-gradient(#04519b,#044687 60%,#033769);background-image:linear-gradient(#04519b,#044687 60%,#033769);background-repeat:no-repeat;border-bottom:1px solid #022241;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff04519b',endColorstr='#ff033769',GradientType=0);filter:none}.btn{text-shadow:0 1px 0 rgba(0,0,0,0.1)}.btn .caret{border-top-color:#fff}.btn-default{background-image:-webkit-linear-gradient(#fff,#fff 60%,#f5f5f5);background-image:linear-gradient(#fff,#fff 60%,#f5f5f5);background-repeat:no-repeat;border-bottom:1px solid #e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff5f5f5',GradientType=0);filter:none}.btn-default:hover{color:#555}.btn-default .caret{border-top-color:#555}.btn-default{background-image:-webkit-linear-gradient(#fff,#fff 60%,#f5f5f5);background-image:linear-gradient(#fff,#fff 60%,#f5f5f5);background-repeat:no-repeat;border-bottom:1px solid #e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff',endColorstr='#fff5f5f5',GradientType=0);filter:none}.btn-primary{background-image:-webkit-linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5);background-image:linear-gradient(#54b4eb,#2fa4e7 60%,#1d9ce5);background-repeat:no-repeat;border-bottom:1px solid #178acc;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff54b4eb',endColorstr='#ff1d9ce5',GradientType=0);filter:none}.btn-success{background-image:-webkit-linear-gradient(#88c149,#73a839 60%,#699934);background-image:linear-gradient(#88c149,#73a839 60%,#699934);background-repeat:no-repeat;border-bottom:1px solid #59822c;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff88c149',endColorstr='#ff699934',GradientType=0);filter:none}.btn-info{background-image:-webkit-linear-gradient(#04519b,#033c73 60%,#02325f);background-image:linear-gradient(#04519b,#033c73 60%,#02325f);background-repeat:no-repeat;border-bottom:1px solid #022241;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff04519b',endColorstr='#ff02325f',GradientType=0);filter:none}.btn-warning{background-image:-webkit-linear-gradient(#ff6707,#dd5600 60%,#c94e00);background-image:linear-gradient(#ff6707,#dd5600 60%,#c94e00);background-repeat:no-repeat;border-bottom:1px solid #aa4200;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff6707',endColorstr='#ffc94e00',GradientType=0);filter:none}.btn-danger{background-image:-webkit-linear-gradient(#e12b31,#c71c22 60%,#b5191f);background-image:linear-gradient(#e12b31,#c71c22 60%,#b5191f);background-repeat:no-repeat;border-bottom:1px solid #9a161a;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe12b31',endColorstr='#ffb5191f',GradientType=0);filter:none}.pagination .active>a,.pagination .active>a:hover{border-color:#ddd}.panel-primary .panel-heading,.panel-success .panel-heading,.panel-warning .panel-heading,.panel-danger .panel-heading,.panel-info .panel-heading,.panel-primary .panel-title,.panel-success .panel-title,.panel-warning .panel-title,.panel-danger .panel-title,.panel-info .panel-title{color:#fff}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.clearfix:before,.clearfix:after{display:table;content:" "}.clearfix:after{clear:both}.center-block{display:block;margin-right:auto;margin-left:auto}.pull-right{float:right!important}.pull-left{float:left!important}.hide{display:none!important}.show{display:block!important}.invisible{visibility:hidden}.text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.hidden{display:none!important;visibility:hidden!important}.affix{position:fixed} \ No newline at end of file diff --git a/node_modules/neataptic/docs/css/font-awesome-4.5.0.css b/node_modules/neataptic/docs/css/font-awesome-4.5.0.css deleted file mode 100644 index d0603cb..0000000 --- a/node_modules/neataptic/docs/css/font-awesome-4.5.0.css +++ /dev/null @@ -1,4 +0,0 @@ -/*! - * Font Awesome 4.5.0 by @davegandy - http://fontawesome.io - @fontawesome - * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) - */@font-face{font-family:'FontAwesome';src:url('../fonts/fontawesome-webfont.eot?v=4.5.0');src:url('../fonts/fontawesome-webfont.eot?#iefix&v=4.5.0') format('embedded-opentype'),url('../fonts/fontawesome-webfont.woff2?v=4.5.0') format('woff2'),url('../fonts/fontawesome-webfont.woff?v=4.5.0') format('woff'),url('../fonts/fontawesome-webfont.ttf?v=4.5.0') format('truetype'),url('../fonts/fontawesome-webfont.svg?v=4.5.0#fontawesomeregular') format('svg');font-weight:normal;font-style:normal}.fa{display:inline-block;font:normal normal normal 14px/1 FontAwesome;font-size:inherit;text-rendering:auto;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-lg{font-size:1.33333333em;line-height:.75em;vertical-align:-15%}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-fw{width:1.28571429em;text-align:center}.fa-ul{padding-left:0;margin-left:2.14285714em;list-style-type:none}.fa-ul>li{position:relative}.fa-li{position:absolute;left:-2.14285714em;width:2.14285714em;top:.14285714em;text-align:center}.fa-li.fa-lg{left:-1.85714286em}.fa-border{padding:.2em .25em .15em;border:solid .08em #eee;border-radius:.1em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left{margin-right:.3em}.fa.fa-pull-right{margin-left:.3em}.pull-right{float:right}.pull-left{float:left}.fa.pull-left{margin-right:.3em}.fa.pull-right{margin-left:.3em}.fa-spin{-webkit-animation:fa-spin 2s infinite linear;animation:fa-spin 2s infinite linear}.fa-pulse{-webkit-animation:fa-spin 1s infinite steps(8);animation:fa-spin 1s infinite steps(8)}@-webkit-keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}@keyframes fa-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}.fa-rotate-90{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);-webkit-transform:rotate(90deg);-ms-transform:rotate(90deg);transform:rotate(90deg)}.fa-rotate-180{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.fa-rotate-270{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);-webkit-transform:rotate(270deg);-ms-transform:rotate(270deg);transform:rotate(270deg)}.fa-flip-horizontal{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1);-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.fa-flip-vertical{filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1);-webkit-transform:scale(1, -1);-ms-transform:scale(1, -1);transform:scale(1, -1)}:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270,:root .fa-flip-horizontal,:root .fa-flip-vertical{filter:none}.fa-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:middle}.fa-stack-1x,.fa-stack-2x{position:absolute;left:0;width:100%;text-align:center}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-glass:before{content:"\f000"}.fa-music:before{content:"\f001"}.fa-search:before{content:"\f002"}.fa-envelope-o:before{content:"\f003"}.fa-heart:before{content:"\f004"}.fa-star:before{content:"\f005"}.fa-star-o:before{content:"\f006"}.fa-user:before{content:"\f007"}.fa-film:before{content:"\f008"}.fa-th-large:before{content:"\f009"}.fa-th:before{content:"\f00a"}.fa-th-list:before{content:"\f00b"}.fa-check:before{content:"\f00c"}.fa-remove:before,.fa-close:before,.fa-times:before{content:"\f00d"}.fa-search-plus:before{content:"\f00e"}.fa-search-minus:before{content:"\f010"}.fa-power-off:before{content:"\f011"}.fa-signal:before{content:"\f012"}.fa-gear:before,.fa-cog:before{content:"\f013"}.fa-trash-o:before{content:"\f014"}.fa-home:before{content:"\f015"}.fa-file-o:before{content:"\f016"}.fa-clock-o:before{content:"\f017"}.fa-road:before{content:"\f018"}.fa-download:before{content:"\f019"}.fa-arrow-circle-o-down:before{content:"\f01a"}.fa-arrow-circle-o-up:before{content:"\f01b"}.fa-inbox:before{content:"\f01c"}.fa-play-circle-o:before{content:"\f01d"}.fa-rotate-right:before,.fa-repeat:before{content:"\f01e"}.fa-refresh:before{content:"\f021"}.fa-list-alt:before{content:"\f022"}.fa-lock:before{content:"\f023"}.fa-flag:before{content:"\f024"}.fa-headphones:before{content:"\f025"}.fa-volume-off:before{content:"\f026"}.fa-volume-down:before{content:"\f027"}.fa-volume-up:before{content:"\f028"}.fa-qrcode:before{content:"\f029"}.fa-barcode:before{content:"\f02a"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-book:before{content:"\f02d"}.fa-bookmark:before{content:"\f02e"}.fa-print:before{content:"\f02f"}.fa-camera:before{content:"\f030"}.fa-font:before{content:"\f031"}.fa-bold:before{content:"\f032"}.fa-italic:before{content:"\f033"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-align-left:before{content:"\f036"}.fa-align-center:before{content:"\f037"}.fa-align-right:before{content:"\f038"}.fa-align-justify:before{content:"\f039"}.fa-list:before{content:"\f03a"}.fa-dedent:before,.fa-outdent:before{content:"\f03b"}.fa-indent:before{content:"\f03c"}.fa-video-camera:before{content:"\f03d"}.fa-photo:before,.fa-image:before,.fa-picture-o:before{content:"\f03e"}.fa-pencil:before{content:"\f040"}.fa-map-marker:before{content:"\f041"}.fa-adjust:before{content:"\f042"}.fa-tint:before{content:"\f043"}.fa-edit:before,.fa-pencil-square-o:before{content:"\f044"}.fa-share-square-o:before{content:"\f045"}.fa-check-square-o:before{content:"\f046"}.fa-arrows:before{content:"\f047"}.fa-step-backward:before{content:"\f048"}.fa-fast-backward:before{content:"\f049"}.fa-backward:before{content:"\f04a"}.fa-play:before{content:"\f04b"}.fa-pause:before{content:"\f04c"}.fa-stop:before{content:"\f04d"}.fa-forward:before{content:"\f04e"}.fa-fast-forward:before{content:"\f050"}.fa-step-forward:before{content:"\f051"}.fa-eject:before{content:"\f052"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-plus-circle:before{content:"\f055"}.fa-minus-circle:before{content:"\f056"}.fa-times-circle:before{content:"\f057"}.fa-check-circle:before{content:"\f058"}.fa-question-circle:before{content:"\f059"}.fa-info-circle:before{content:"\f05a"}.fa-crosshairs:before{content:"\f05b"}.fa-times-circle-o:before{content:"\f05c"}.fa-check-circle-o:before{content:"\f05d"}.fa-ban:before{content:"\f05e"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrow-down:before{content:"\f063"}.fa-mail-forward:before,.fa-share:before{content:"\f064"}.fa-expand:before{content:"\f065"}.fa-compress:before{content:"\f066"}.fa-plus:before{content:"\f067"}.fa-minus:before{content:"\f068"}.fa-asterisk:before{content:"\f069"}.fa-exclamation-circle:before{content:"\f06a"}.fa-gift:before{content:"\f06b"}.fa-leaf:before{content:"\f06c"}.fa-fire:before{content:"\f06d"}.fa-eye:before{content:"\f06e"}.fa-eye-slash:before{content:"\f070"}.fa-warning:before,.fa-exclamation-triangle:before{content:"\f071"}.fa-plane:before{content:"\f072"}.fa-calendar:before{content:"\f073"}.fa-random:before{content:"\f074"}.fa-comment:before{content:"\f075"}.fa-magnet:before{content:"\f076"}.fa-chevron-up:before{content:"\f077"}.fa-chevron-down:before{content:"\f078"}.fa-retweet:before{content:"\f079"}.fa-shopping-cart:before{content:"\f07a"}.fa-folder:before{content:"\f07b"}.fa-folder-open:before{content:"\f07c"}.fa-arrows-v:before{content:"\f07d"}.fa-arrows-h:before{content:"\f07e"}.fa-bar-chart-o:before,.fa-bar-chart:before{content:"\f080"}.fa-twitter-square:before{content:"\f081"}.fa-facebook-square:before{content:"\f082"}.fa-camera-retro:before{content:"\f083"}.fa-key:before{content:"\f084"}.fa-gears:before,.fa-cogs:before{content:"\f085"}.fa-comments:before{content:"\f086"}.fa-thumbs-o-up:before{content:"\f087"}.fa-thumbs-o-down:before{content:"\f088"}.fa-star-half:before{content:"\f089"}.fa-heart-o:before{content:"\f08a"}.fa-sign-out:before{content:"\f08b"}.fa-linkedin-square:before{content:"\f08c"}.fa-thumb-tack:before{content:"\f08d"}.fa-external-link:before{content:"\f08e"}.fa-sign-in:before{content:"\f090"}.fa-trophy:before{content:"\f091"}.fa-github-square:before{content:"\f092"}.fa-upload:before{content:"\f093"}.fa-lemon-o:before{content:"\f094"}.fa-phone:before{content:"\f095"}.fa-square-o:before{content:"\f096"}.fa-bookmark-o:before{content:"\f097"}.fa-phone-square:before{content:"\f098"}.fa-twitter:before{content:"\f099"}.fa-facebook-f:before,.fa-facebook:before{content:"\f09a"}.fa-github:before{content:"\f09b"}.fa-unlock:before{content:"\f09c"}.fa-credit-card:before{content:"\f09d"}.fa-feed:before,.fa-rss:before{content:"\f09e"}.fa-hdd-o:before{content:"\f0a0"}.fa-bullhorn:before{content:"\f0a1"}.fa-bell:before{content:"\f0f3"}.fa-certificate:before{content:"\f0a3"}.fa-hand-o-right:before{content:"\f0a4"}.fa-hand-o-left:before{content:"\f0a5"}.fa-hand-o-up:before{content:"\f0a6"}.fa-hand-o-down:before{content:"\f0a7"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-globe:before{content:"\f0ac"}.fa-wrench:before{content:"\f0ad"}.fa-tasks:before{content:"\f0ae"}.fa-filter:before{content:"\f0b0"}.fa-briefcase:before{content:"\f0b1"}.fa-arrows-alt:before{content:"\f0b2"}.fa-group:before,.fa-users:before{content:"\f0c0"}.fa-chain:before,.fa-link:before{content:"\f0c1"}.fa-cloud:before{content:"\f0c2"}.fa-flask:before{content:"\f0c3"}.fa-cut:before,.fa-scissors:before{content:"\f0c4"}.fa-copy:before,.fa-files-o:before{content:"\f0c5"}.fa-paperclip:before{content:"\f0c6"}.fa-save:before,.fa-floppy-o:before{content:"\f0c7"}.fa-square:before{content:"\f0c8"}.fa-navicon:before,.fa-reorder:before,.fa-bars:before{content:"\f0c9"}.fa-list-ul:before{content:"\f0ca"}.fa-list-ol:before{content:"\f0cb"}.fa-strikethrough:before{content:"\f0cc"}.fa-underline:before{content:"\f0cd"}.fa-table:before{content:"\f0ce"}.fa-magic:before{content:"\f0d0"}.fa-truck:before{content:"\f0d1"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-square:before{content:"\f0d3"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-plus:before{content:"\f0d5"}.fa-money:before{content:"\f0d6"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-up:before{content:"\f0d8"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-columns:before{content:"\f0db"}.fa-unsorted:before,.fa-sort:before{content:"\f0dc"}.fa-sort-down:before,.fa-sort-desc:before{content:"\f0dd"}.fa-sort-up:before,.fa-sort-asc:before{content:"\f0de"}.fa-envelope:before{content:"\f0e0"}.fa-linkedin:before{content:"\f0e1"}.fa-rotate-left:before,.fa-undo:before{content:"\f0e2"}.fa-legal:before,.fa-gavel:before{content:"\f0e3"}.fa-dashboard:before,.fa-tachometer:before{content:"\f0e4"}.fa-comment-o:before{content:"\f0e5"}.fa-comments-o:before{content:"\f0e6"}.fa-flash:before,.fa-bolt:before{content:"\f0e7"}.fa-sitemap:before{content:"\f0e8"}.fa-umbrella:before{content:"\f0e9"}.fa-paste:before,.fa-clipboard:before{content:"\f0ea"}.fa-lightbulb-o:before{content:"\f0eb"}.fa-exchange:before{content:"\f0ec"}.fa-cloud-download:before{content:"\f0ed"}.fa-cloud-upload:before{content:"\f0ee"}.fa-user-md:before{content:"\f0f0"}.fa-stethoscope:before{content:"\f0f1"}.fa-suitcase:before{content:"\f0f2"}.fa-bell-o:before{content:"\f0a2"}.fa-coffee:before{content:"\f0f4"}.fa-cutlery:before{content:"\f0f5"}.fa-file-text-o:before{content:"\f0f6"}.fa-building-o:before{content:"\f0f7"}.fa-hospital-o:before{content:"\f0f8"}.fa-ambulance:before{content:"\f0f9"}.fa-medkit:before{content:"\f0fa"}.fa-fighter-jet:before{content:"\f0fb"}.fa-beer:before{content:"\f0fc"}.fa-h-square:before{content:"\f0fd"}.fa-plus-square:before{content:"\f0fe"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angle-down:before{content:"\f107"}.fa-desktop:before{content:"\f108"}.fa-laptop:before{content:"\f109"}.fa-tablet:before{content:"\f10a"}.fa-mobile-phone:before,.fa-mobile:before{content:"\f10b"}.fa-circle-o:before{content:"\f10c"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-spinner:before{content:"\f110"}.fa-circle:before{content:"\f111"}.fa-mail-reply:before,.fa-reply:before{content:"\f112"}.fa-github-alt:before{content:"\f113"}.fa-folder-o:before{content:"\f114"}.fa-folder-open-o:before{content:"\f115"}.fa-smile-o:before{content:"\f118"}.fa-frown-o:before{content:"\f119"}.fa-meh-o:before{content:"\f11a"}.fa-gamepad:before{content:"\f11b"}.fa-keyboard-o:before{content:"\f11c"}.fa-flag-o:before{content:"\f11d"}.fa-flag-checkered:before{content:"\f11e"}.fa-terminal:before{content:"\f120"}.fa-code:before{content:"\f121"}.fa-mail-reply-all:before,.fa-reply-all:before{content:"\f122"}.fa-star-half-empty:before,.fa-star-half-full:before,.fa-star-half-o:before{content:"\f123"}.fa-location-arrow:before{content:"\f124"}.fa-crop:before{content:"\f125"}.fa-code-fork:before{content:"\f126"}.fa-unlink:before,.fa-chain-broken:before{content:"\f127"}.fa-question:before{content:"\f128"}.fa-info:before{content:"\f129"}.fa-exclamation:before{content:"\f12a"}.fa-superscript:before{content:"\f12b"}.fa-subscript:before{content:"\f12c"}.fa-eraser:before{content:"\f12d"}.fa-puzzle-piece:before{content:"\f12e"}.fa-microphone:before{content:"\f130"}.fa-microphone-slash:before{content:"\f131"}.fa-shield:before{content:"\f132"}.fa-calendar-o:before{content:"\f133"}.fa-fire-extinguisher:before{content:"\f134"}.fa-rocket:before{content:"\f135"}.fa-maxcdn:before{content:"\f136"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-html5:before{content:"\f13b"}.fa-css3:before{content:"\f13c"}.fa-anchor:before{content:"\f13d"}.fa-unlock-alt:before{content:"\f13e"}.fa-bullseye:before{content:"\f140"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-rss-square:before{content:"\f143"}.fa-play-circle:before{content:"\f144"}.fa-ticket:before{content:"\f145"}.fa-minus-square:before{content:"\f146"}.fa-minus-square-o:before{content:"\f147"}.fa-level-up:before{content:"\f148"}.fa-level-down:before{content:"\f149"}.fa-check-square:before{content:"\f14a"}.fa-pencil-square:before{content:"\f14b"}.fa-external-link-square:before{content:"\f14c"}.fa-share-square:before{content:"\f14d"}.fa-compass:before{content:"\f14e"}.fa-toggle-down:before,.fa-caret-square-o-down:before{content:"\f150"}.fa-toggle-up:before,.fa-caret-square-o-up:before{content:"\f151"}.fa-toggle-right:before,.fa-caret-square-o-right:before{content:"\f152"}.fa-euro:before,.fa-eur:before{content:"\f153"}.fa-gbp:before{content:"\f154"}.fa-dollar:before,.fa-usd:before{content:"\f155"}.fa-rupee:before,.fa-inr:before{content:"\f156"}.fa-cny:before,.fa-rmb:before,.fa-yen:before,.fa-jpy:before{content:"\f157"}.fa-ruble:before,.fa-rouble:before,.fa-rub:before{content:"\f158"}.fa-won:before,.fa-krw:before{content:"\f159"}.fa-bitcoin:before,.fa-btc:before{content:"\f15a"}.fa-file:before{content:"\f15b"}.fa-file-text:before{content:"\f15c"}.fa-sort-alpha-asc:before{content:"\f15d"}.fa-sort-alpha-desc:before{content:"\f15e"}.fa-sort-amount-asc:before{content:"\f160"}.fa-sort-amount-desc:before{content:"\f161"}.fa-sort-numeric-asc:before{content:"\f162"}.fa-sort-numeric-desc:before{content:"\f163"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbs-down:before{content:"\f165"}.fa-youtube-square:before{content:"\f166"}.fa-youtube:before{content:"\f167"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-youtube-play:before{content:"\f16a"}.fa-dropbox:before{content:"\f16b"}.fa-stack-overflow:before{content:"\f16c"}.fa-instagram:before{content:"\f16d"}.fa-flickr:before{content:"\f16e"}.fa-adn:before{content:"\f170"}.fa-bitbucket:before{content:"\f171"}.fa-bitbucket-square:before{content:"\f172"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-long-arrow-down:before{content:"\f175"}.fa-long-arrow-up:before{content:"\f176"}.fa-long-arrow-left:before{content:"\f177"}.fa-long-arrow-right:before{content:"\f178"}.fa-apple:before{content:"\f179"}.fa-windows:before{content:"\f17a"}.fa-android:before{content:"\f17b"}.fa-linux:before{content:"\f17c"}.fa-dribbble:before{content:"\f17d"}.fa-skype:before{content:"\f17e"}.fa-foursquare:before{content:"\f180"}.fa-trello:before{content:"\f181"}.fa-female:before{content:"\f182"}.fa-male:before{content:"\f183"}.fa-gittip:before,.fa-gratipay:before{content:"\f184"}.fa-sun-o:before{content:"\f185"}.fa-moon-o:before{content:"\f186"}.fa-archive:before{content:"\f187"}.fa-bug:before{content:"\f188"}.fa-vk:before{content:"\f189"}.fa-weibo:before{content:"\f18a"}.fa-renren:before{content:"\f18b"}.fa-pagelines:before{content:"\f18c"}.fa-stack-exchange:before{content:"\f18d"}.fa-arrow-circle-o-right:before{content:"\f18e"}.fa-arrow-circle-o-left:before{content:"\f190"}.fa-toggle-left:before,.fa-caret-square-o-left:before{content:"\f191"}.fa-dot-circle-o:before{content:"\f192"}.fa-wheelchair:before{content:"\f193"}.fa-vimeo-square:before{content:"\f194"}.fa-turkish-lira:before,.fa-try:before{content:"\f195"}.fa-plus-square-o:before{content:"\f196"}.fa-space-shuttle:before{content:"\f197"}.fa-slack:before{content:"\f198"}.fa-envelope-square:before{content:"\f199"}.fa-wordpress:before{content:"\f19a"}.fa-openid:before{content:"\f19b"}.fa-institution:before,.fa-bank:before,.fa-university:before{content:"\f19c"}.fa-mortar-board:before,.fa-graduation-cap:before{content:"\f19d"}.fa-yahoo:before{content:"\f19e"}.fa-google:before{content:"\f1a0"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-square:before{content:"\f1a2"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-stumbleupon:before{content:"\f1a4"}.fa-delicious:before{content:"\f1a5"}.fa-digg:before{content:"\f1a6"}.fa-pied-piper:before{content:"\f1a7"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-drupal:before{content:"\f1a9"}.fa-joomla:before{content:"\f1aa"}.fa-language:before{content:"\f1ab"}.fa-fax:before{content:"\f1ac"}.fa-building:before{content:"\f1ad"}.fa-child:before{content:"\f1ae"}.fa-paw:before{content:"\f1b0"}.fa-spoon:before{content:"\f1b1"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-recycle:before{content:"\f1b8"}.fa-automobile:before,.fa-car:before{content:"\f1b9"}.fa-cab:before,.fa-taxi:before{content:"\f1ba"}.fa-tree:before{content:"\f1bb"}.fa-spotify:before{content:"\f1bc"}.fa-deviantart:before{content:"\f1bd"}.fa-soundcloud:before{content:"\f1be"}.fa-database:before{content:"\f1c0"}.fa-file-pdf-o:before{content:"\f1c1"}.fa-file-word-o:before{content:"\f1c2"}.fa-file-excel-o:before{content:"\f1c3"}.fa-file-powerpoint-o:before{content:"\f1c4"}.fa-file-photo-o:before,.fa-file-picture-o:before,.fa-file-image-o:before{content:"\f1c5"}.fa-file-zip-o:before,.fa-file-archive-o:before{content:"\f1c6"}.fa-file-sound-o:before,.fa-file-audio-o:before{content:"\f1c7"}.fa-file-movie-o:before,.fa-file-video-o:before{content:"\f1c8"}.fa-file-code-o:before{content:"\f1c9"}.fa-vine:before{content:"\f1ca"}.fa-codepen:before{content:"\f1cb"}.fa-jsfiddle:before{content:"\f1cc"}.fa-life-bouy:before,.fa-life-buoy:before,.fa-life-saver:before,.fa-support:before,.fa-life-ring:before{content:"\f1cd"}.fa-circle-o-notch:before{content:"\f1ce"}.fa-ra:before,.fa-rebel:before{content:"\f1d0"}.fa-ge:before,.fa-empire:before{content:"\f1d1"}.fa-git-square:before{content:"\f1d2"}.fa-git:before{content:"\f1d3"}.fa-y-combinator-square:before,.fa-yc-square:before,.fa-hacker-news:before{content:"\f1d4"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-qq:before{content:"\f1d6"}.fa-wechat:before,.fa-weixin:before{content:"\f1d7"}.fa-send:before,.fa-paper-plane:before{content:"\f1d8"}.fa-send-o:before,.fa-paper-plane-o:before{content:"\f1d9"}.fa-history:before{content:"\f1da"}.fa-circle-thin:before{content:"\f1db"}.fa-header:before{content:"\f1dc"}.fa-paragraph:before{content:"\f1dd"}.fa-sliders:before{content:"\f1de"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-bomb:before{content:"\f1e2"}.fa-soccer-ball-o:before,.fa-futbol-o:before{content:"\f1e3"}.fa-tty:before{content:"\f1e4"}.fa-binoculars:before{content:"\f1e5"}.fa-plug:before{content:"\f1e6"}.fa-slideshare:before{content:"\f1e7"}.fa-twitch:before{content:"\f1e8"}.fa-yelp:before{content:"\f1e9"}.fa-newspaper-o:before{content:"\f1ea"}.fa-wifi:before{content:"\f1eb"}.fa-calculator:before{content:"\f1ec"}.fa-paypal:before{content:"\f1ed"}.fa-google-wallet:before{content:"\f1ee"}.fa-cc-visa:before{content:"\f1f0"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-bell-slash:before{content:"\f1f6"}.fa-bell-slash-o:before{content:"\f1f7"}.fa-trash:before{content:"\f1f8"}.fa-copyright:before{content:"\f1f9"}.fa-at:before{content:"\f1fa"}.fa-eyedropper:before{content:"\f1fb"}.fa-paint-brush:before{content:"\f1fc"}.fa-birthday-cake:before{content:"\f1fd"}.fa-area-chart:before{content:"\f1fe"}.fa-pie-chart:before{content:"\f200"}.fa-line-chart:before{content:"\f201"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-bicycle:before{content:"\f206"}.fa-bus:before{content:"\f207"}.fa-ioxhost:before{content:"\f208"}.fa-angellist:before{content:"\f209"}.fa-cc:before{content:"\f20a"}.fa-shekel:before,.fa-sheqel:before,.fa-ils:before{content:"\f20b"}.fa-meanpath:before{content:"\f20c"}.fa-buysellads:before{content:"\f20d"}.fa-connectdevelop:before{content:"\f20e"}.fa-dashcube:before{content:"\f210"}.fa-forumbee:before{content:"\f211"}.fa-leanpub:before{content:"\f212"}.fa-sellsy:before{content:"\f213"}.fa-shirtsinbulk:before{content:"\f214"}.fa-simplybuilt:before{content:"\f215"}.fa-skyatlas:before{content:"\f216"}.fa-cart-plus:before{content:"\f217"}.fa-cart-arrow-down:before{content:"\f218"}.fa-diamond:before{content:"\f219"}.fa-ship:before{content:"\f21a"}.fa-user-secret:before{content:"\f21b"}.fa-motorcycle:before{content:"\f21c"}.fa-street-view:before{content:"\f21d"}.fa-heartbeat:before{content:"\f21e"}.fa-venus:before{content:"\f221"}.fa-mars:before{content:"\f222"}.fa-mercury:before{content:"\f223"}.fa-intersex:before,.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-venus-double:before{content:"\f226"}.fa-mars-double:before{content:"\f227"}.fa-venus-mars:before{content:"\f228"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-neuter:before{content:"\f22c"}.fa-genderless:before{content:"\f22d"}.fa-facebook-official:before{content:"\f230"}.fa-pinterest-p:before{content:"\f231"}.fa-whatsapp:before{content:"\f232"}.fa-server:before{content:"\f233"}.fa-user-plus:before{content:"\f234"}.fa-user-times:before{content:"\f235"}.fa-hotel:before,.fa-bed:before{content:"\f236"}.fa-viacoin:before{content:"\f237"}.fa-train:before{content:"\f238"}.fa-subway:before{content:"\f239"}.fa-medium:before{content:"\f23a"}.fa-yc:before,.fa-y-combinator:before{content:"\f23b"}.fa-optin-monster:before{content:"\f23c"}.fa-opencart:before{content:"\f23d"}.fa-expeditedssl:before{content:"\f23e"}.fa-battery-4:before,.fa-battery-full:before{content:"\f240"}.fa-battery-3:before,.fa-battery-three-quarters:before{content:"\f241"}.fa-battery-2:before,.fa-battery-half:before{content:"\f242"}.fa-battery-1:before,.fa-battery-quarter:before{content:"\f243"}.fa-battery-0:before,.fa-battery-empty:before{content:"\f244"}.fa-mouse-pointer:before{content:"\f245"}.fa-i-cursor:before{content:"\f246"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-sticky-note:before{content:"\f249"}.fa-sticky-note-o:before{content:"\f24a"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-diners-club:before{content:"\f24c"}.fa-clone:before{content:"\f24d"}.fa-balance-scale:before{content:"\f24e"}.fa-hourglass-o:before{content:"\f250"}.fa-hourglass-1:before,.fa-hourglass-start:before{content:"\f251"}.fa-hourglass-2:before,.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-3:before,.fa-hourglass-end:before{content:"\f253"}.fa-hourglass:before{content:"\f254"}.fa-hand-grab-o:before,.fa-hand-rock-o:before{content:"\f255"}.fa-hand-stop-o:before,.fa-hand-paper-o:before{content:"\f256"}.fa-hand-scissors-o:before{content:"\f257"}.fa-hand-lizard-o:before{content:"\f258"}.fa-hand-spock-o:before{content:"\f259"}.fa-hand-pointer-o:before{content:"\f25a"}.fa-hand-peace-o:before{content:"\f25b"}.fa-trademark:before{content:"\f25c"}.fa-registered:before{content:"\f25d"}.fa-creative-commons:before{content:"\f25e"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-tripadvisor:before{content:"\f262"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-get-pocket:before{content:"\f265"}.fa-wikipedia-w:before{content:"\f266"}.fa-safari:before{content:"\f267"}.fa-chrome:before{content:"\f268"}.fa-firefox:before{content:"\f269"}.fa-opera:before{content:"\f26a"}.fa-internet-explorer:before{content:"\f26b"}.fa-tv:before,.fa-television:before{content:"\f26c"}.fa-contao:before{content:"\f26d"}.fa-500px:before{content:"\f26e"}.fa-amazon:before{content:"\f270"}.fa-calendar-plus-o:before{content:"\f271"}.fa-calendar-minus-o:before{content:"\f272"}.fa-calendar-times-o:before{content:"\f273"}.fa-calendar-check-o:before{content:"\f274"}.fa-industry:before{content:"\f275"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-map-o:before{content:"\f278"}.fa-map:before{content:"\f279"}.fa-commenting:before{content:"\f27a"}.fa-commenting-o:before{content:"\f27b"}.fa-houzz:before{content:"\f27c"}.fa-vimeo:before{content:"\f27d"}.fa-black-tie:before{content:"\f27e"}.fa-fonticons:before{content:"\f280"}.fa-reddit-alien:before{content:"\f281"}.fa-edge:before{content:"\f282"}.fa-credit-card-alt:before{content:"\f283"}.fa-codiepie:before{content:"\f284"}.fa-modx:before{content:"\f285"}.fa-fort-awesome:before{content:"\f286"}.fa-usb:before{content:"\f287"}.fa-product-hunt:before{content:"\f288"}.fa-mixcloud:before{content:"\f289"}.fa-scribd:before{content:"\f28a"}.fa-pause-circle:before{content:"\f28b"}.fa-pause-circle-o:before{content:"\f28c"}.fa-stop-circle:before{content:"\f28d"}.fa-stop-circle-o:before{content:"\f28e"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-hashtag:before{content:"\f292"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-percent:before{content:"\f295"} diff --git a/node_modules/neataptic/docs/css/highlight.css b/node_modules/neataptic/docs/css/highlight.css deleted file mode 100644 index 0ae40a7..0000000 --- a/node_modules/neataptic/docs/css/highlight.css +++ /dev/null @@ -1,124 +0,0 @@ -/* -This is the GitHub theme for highlight.js - -github.com style (c) Vasily Polovnyov - -*/ - -.hljs { - display: block; - overflow-x: auto; - color: #333; - -webkit-text-size-adjust: none; -} - -.hljs-comment, -.diff .hljs-header, -.hljs-javadoc { - color: #998; - font-style: italic; -} - -.hljs-keyword, -.css .rule .hljs-keyword, -.hljs-winutils, -.nginx .hljs-title, -.hljs-subst, -.hljs-request, -.hljs-status { - color: #333; - font-weight: bold; -} - -.hljs-number, -.hljs-hexcolor, -.ruby .hljs-constant { - color: #008080; -} - -.hljs-string, -.hljs-tag .hljs-value, -.hljs-phpdoc, -.hljs-dartdoc, -.tex .hljs-formula { - color: #d14; -} - -.hljs-title, -.hljs-id, -.scss .hljs-preprocessor { - color: #900; - font-weight: bold; -} - -.hljs-list .hljs-keyword, -.hljs-subst { - font-weight: normal; -} - -.hljs-class .hljs-title, -.hljs-type, -.vhdl .hljs-literal, -.tex .hljs-command { - color: #458; - font-weight: bold; -} - -.hljs-tag, -.hljs-tag .hljs-title, -.hljs-rule .hljs-property, -.django .hljs-tag .hljs-keyword { - color: #000080; - font-weight: normal; -} - -.hljs-attribute, -.hljs-variable, -.lisp .hljs-body, -.hljs-name { - color: #008080; -} - -.hljs-regexp { - color: #009926; -} - -.hljs-symbol, -.ruby .hljs-symbol .hljs-string, -.lisp .hljs-keyword, -.clojure .hljs-keyword, -.scheme .hljs-keyword, -.tex .hljs-special, -.hljs-prompt { - color: #990073; -} - -.hljs-built_in { - color: #0086b3; -} - -.hljs-preprocessor, -.hljs-pragma, -.hljs-pi, -.hljs-doctype, -.hljs-shebang, -.hljs-cdata { - color: #999; - font-weight: bold; -} - -.hljs-deletion { - background: #fdd; -} - -.hljs-addition { - background: #dfd; -} - -.diff .hljs-change { - background: #0086b3; -} - -.hljs-chunk { - color: #aaa; -} diff --git a/node_modules/neataptic/docs/custom.css b/node_modules/neataptic/docs/custom.css deleted file mode 100644 index e95974d..0000000 --- a/node_modules/neataptic/docs/custom.css +++ /dev/null @@ -1,117 +0,0 @@ -html, body { - height: 100%; -} - -body { - font-family: 'Roboto', sans-serif; - font-size: 150%; -} -.brand{ - color: white; - font-size: 20px; - font-weight: 500; - letter-spacing: 1px; -} -.nav > ul> li { - list-style-type: none; -} -.nav > ul> li > a { - text-decoration: none; -} -/* navbar */ -.navbar-default { - background-color: #2C3963; - border-bottom: 2px solid white; -} -/* Title */ -.navbar-default .navbar-brand { - color: white; -} -.navbar-default .navbar-brand:hover, -.navbar-default .navbar-brand:focus { - color: #5E5E5E; -} -/* Link */ -.navbar-default .navbar-nav > li > a { - color: rgba(255,255,255,.8); -} -.navbar-default .navbar-nav > li > a:hover, -.navbar-default .navbar-nav > li > a:focus { - color: white; -} -.navbar-default .navbar-nav > .active > a, -.navbar-default .navbar-nav > .active > a:hover, -.navbar-default .navbar-nav > .active > a:focus { - color: white; - background-color: #2C3963; - border-bottom: 2px solid white; -} - -/* Custom coloring */ -.btn-primary{ - background-color: #2C3963; - border-color: #2F3D68; -} - -.panel-warning > .panel-heading{ - background-color: #2C3963; - border-color: #2C3963; - color: white; -} -.panel-warning{ - border-color: #2C3963; -} - -/* Homepage */ -.jumbotron.vertical-center { - margin-bottom: 0; /* Remove the default bottom margin of .jumbotron */ - background-color: #2C3963; -} -.vertical-center { - min-height: 100%; /* Fallback for vh unit */ - min-height: 100vh; /* You might also want to use - 'height' property instead. - - Note that for percentage values of - 'height' or 'min-height' properties, - the 'height' of the parent element - should be specified explicitly. - - In this case the parent of '.vertical-center' - is the element */ - - /* Make it a flex container */ - display: -webkit-box; - display: -moz-box; - display: -ms-flexbox; - display: -webkit-flex; - display: flex; - - /* Align the bootstrap's container vertically */ - -webkit-box-align : center; - -webkit-align-items : center; - -moz-box-align : center; - -ms-flex-align : center; - align-items : center; - - /* In legacy web browsers such as Firefox 9 - we need to specify the width of the flex container */ - width: 100%; - - /* Also 'margin: 0 auto' doesn't have any effect on flex items in such web browsers - hence the bootstrap's container won't be aligned to the center anymore. - - Therefore, we should use the following declarations to get it centered again */ - -webkit-box-pack : center; - -moz-box-pack : center; - -ms-flex-pack : center; - -webkit-justify-content : center; - justify-content : center; -} -.welcome { - color: white; -} -.subtitle { - padding: 0; - margin: 0; -} diff --git a/node_modules/neataptic/docs/docs/architecture/architecture/index.html b/node_modules/neataptic/docs/docs/architecture/architecture/index.html deleted file mode 100644 index 2037496..0000000 --- a/node_modules/neataptic/docs/docs/architecture/architecture/index.html +++ /dev/null @@ -1,321 +0,0 @@ - - - Neataptic.js - Architecture - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Architecture

                  -

                  Edit on Github

                  -
                  -

                  If you want to built your completely custom neural network; this is the place to be. -You can build your network from the bottom, using nodes and connections, or you can -ease up the process by using groups and layers.

                  - -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/architecture/connection/index.html b/node_modules/neataptic/docs/docs/architecture/connection/index.html deleted file mode 100644 index f556129..0000000 --- a/node_modules/neataptic/docs/docs/architecture/connection/index.html +++ /dev/null @@ -1,361 +0,0 @@ - - - Neataptic.js - Connection - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Connection

                  -

                  Edit on Github

                  -
                  -

                  A connection instance defines the connection between two nodes. All you have to do is pass on a from and to node, and optionally a weight.

                  -
                  var B = new Node();
                  -var C = new Node();
                  -var connection = new Connection(A, B, 0.5);
                  -
                  - -

                  Connection properties:

                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  Propertycontains
                  fromconnection origin node
                  toconnection destination node
                  weightthe weight of the connection
                  gaterthe node gating this connection
                  gainfor gating, gets multiplied with weight
                  -

                  Connection methods

                  -

                  There are three connection methods:

                  -
                    -
                  • methods.connection.ALL_TO_ALL connects all nodes from group x to all nodes from group y
                  • -
                  • methods.connection.ALL_TO_ELSE connects every node from group x to all nodes in the same group except itself
                  • -
                  • methods.connection.ONE_TO_ONE connects every node in group x to one node in group y
                  • -
                  -

                  Every one of these connection methods can also be used on the group itself! (x.connect(x, METHOD))

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/architecture/construct/index.html b/node_modules/neataptic/docs/docs/architecture/construct/index.html deleted file mode 100644 index d3f50b9..0000000 --- a/node_modules/neataptic/docs/docs/architecture/construct/index.html +++ /dev/null @@ -1,351 +0,0 @@ - - - Neataptic.js - Construct - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Construct

                  -

                  Edit on Github

                  -
                  -

                  For example, I want to have a network that looks like a square:

                  -
                  var A = new Node();
                  -var B = new Node();
                  -var C = new Node();
                  -var D = new Node();
                  -
                  -// Create connections
                  -A.connect(B);
                  -A.connect(C);
                  -B.connect(D);
                  -C.connect(D);
                  -
                  -// Construct a network
                  -var network = architect.Construct([A, B, C, D]);
                  -
                  - -

                  And voila, basically a square, but stretched out, right?

                  -

                  Square

                  -

                  The construct() function looks for nodes that have no input connections, and labels them as an input node. The same for output nodes: it looks for nodes without an output connection (and gating connection), and labels them as an output node!

                  -

                  You can also create networks with groups! This speeds up the creation process and saves lines of code.

                  -
                  // Initialise groups of nodes
                  -var A = new Group(4);
                  -var B = new Group(2);
                  -var C = new Group(6);
                  -
                  -// Create connections between the groups
                  -A.connect(B);
                  -A.connect(C);
                  -B.connect(C);
                  -
                  -// Construct a network
                  -var network = architect.Construct([A, B, C, D]);
                  -
                  - -

                  Keep in mind that you must always specify your input groups/nodes in activation order. Input and output nodes will automatically get sorted out, but all hidden nodes will be activated in the order that they were given.

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/architecture/group/index.html b/node_modules/neataptic/docs/docs/architecture/group/index.html deleted file mode 100644 index d34f28b..0000000 --- a/node_modules/neataptic/docs/docs/architecture/group/index.html +++ /dev/null @@ -1,420 +0,0 @@ - - - Neataptic.js - Group - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Group

                  -

                  Edit on Github

                  -
                  -

                  A group instance denotes a group of nodes. Beware: once a group has been used to construct a network, the groups will fall apart into individual nodes. They are purely for the creation and development of networks. A group can be created like this:

                  -
                  // A group with 5 nodes
                  -var A = new Group(5);
                  -
                  - -

                  Group properties:

                  - - - - - - - - - - - - - - - - - -
                  Propertycontains
                  nodesan array of all nodes in the group
                  connectionsdictionary with connections
                  -

                  activate

                  -

                  Will activate all the nodes in the network.

                  -
                  myGroup.activate();
                  -
                  -// or (array length must be same length as nodes in group)
                  -myGroup.activate([1, 0, 1]);
                  -
                  - -

                  propagate

                  -

                  Will backpropagate all nodes in the group, make sure the group receives input from another group or node!

                  -
                  myGroup.propagate(rate, momentum, target);
                  -
                  - -

                  The target argument is optional. An example would be:

                  -
                  var A = new Group(2);
                  -var B = new Group(3);
                  -
                  -A.connect(B);
                  -
                  -A.activate([1,0]); // set the input
                  -B.activate(); // get the output
                  -
                  -// Then teach the network with learning rate and wanted output
                  -B.propagate(0.3, 0.9, [0,1]);
                  -
                  - -

                  The default value for momentum is 0. Read more about momentum on the -regularization page.

                  -

                  connect

                  -

                  Creates connections between this group and another group or node. There are different connection methods for groups, check them out here.

                  -
                  var A = new Group(4);
                  -var B = new Group(5);
                  -
                  -A.connect(B, methods.connection.ALL_TO_ALL); // specifying a method is optional
                  -
                  - -

                  disconnect

                  -

                  (not yet implemented)

                  -

                  gate

                  -

                  Makes the nodes in a group gate an array of connections between two other groups. You have to specify a gating method, which can be found here.

                  -
                  var A = new Group(2);
                  -var B = new Group(6);
                  -
                  -var connections = A.connect(B);
                  -
                  -var C = new Group(2);
                  -
                  -// Gate the connections between groups A and B
                  -C.gate(connections, methods.gating.INPUT);
                  -
                  - -

                  set

                  -

                  Sets the properties of all nodes in the group to the given values, e.g.:

                  -
                  var group = new Group(4);
                  -
                  -// All nodes in 'group' now have a bias of 1
                  -group.set({bias: 1});
                  -
                  - -

                  disconnect

                  -

                  Disconnects the group from another group or node. Can be twosided.

                  -
                  var A = new Group(4);
                  -var B = new Node();
                  -
                  -// Connect them
                  -A.connect(B);
                  -
                  -// Disconnect them
                  -A.disconnect(B);
                  -
                  -// Twosided connection
                  -A.connect(B);
                  -B.connect(A);
                  -
                  -// Disconnect from both sides
                  -A.disconnect(B, true);
                  -
                  - -

                  clear

                  -

                  Clears the context of the group. Useful for predicting timeseries with LSTM's.

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/architecture/layer/index.html b/node_modules/neataptic/docs/docs/architecture/layer/index.html deleted file mode 100644 index bdfca6b..0000000 --- a/node_modules/neataptic/docs/docs/architecture/layer/index.html +++ /dev/null @@ -1,375 +0,0 @@ - - - Neataptic.js - Layer - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Layer

                  -

                  Edit on Github

                  -
                  -

                  Layers are pre-built architectures that allow you to combine different network -architectures into óne network. At this moment, there are 3 layers (more to come soon!):

                  -
                  Layer.Dense
                  -Layer.LSTM
                  -Layer.GRU
                  -Layer.Memory
                  -
                  - -

                  Check out the options and details for each layer below.

                  -

                  Constructing your own network with layers

                  -

                  You should always start your network with a Dense layer and always end it with -a Dense layer. You can connect layers with each other just like you can connect -nodes and groups with each other. This is an example of a custom architecture -built with layers:

                  -
                  var input = new Layer.Dense(1);
                  -var hidden1 = new Layer.LSTM(5);
                  -var hidden2 = new Layer.GRU(1);
                  -var output = new Layer.Dense(1);
                  -
                  -// connect however you want
                  -input.connect(hidden1);
                  -hidden1.connect(hidden2);
                  -hidden2.connect(output);
                  -
                  -var network = architect.Construct([input, hidden1, hidden2, output]);
                  -
                  - -

                  Layer.Dense

                  -

                  The dense layer is a regular layer.

                  -
                  var layer = new Layer.Dense(size);
                  -
                  - -

                  Layer.LSTM

                  -

                  The LSTM layer is very useful for detecting and predicting patterns over long -time lags. This is a recurrent layer. More info? Check out the LSTM page.

                  -
                  var layer = new Layer.LSTM(size);
                  -
                  - -

                  Be aware that using Layer.LSTM is worse than using architect.LSTM. See issue #25.

                  -

                  Layer.GRU

                  -

                  The GRU layer is similar to the LSTM layer, however it has no memory cell and only -two gates. It is also a recurrent layer that is excellent for timeseries prediction. -More info? Check out the GRU page.

                  -
                  var layer = new Layer.GRU(size);
                  -
                  - -

                  Layer.Memory

                  -

                  The Memory layer is very useful if you want your network to remember a number of -previous inputs in an absolute way. For example, if you set the memory option to -3, it will remember the last 3 inputs in the same state as they were inputted.

                  -
                  var layer = new Layer.Memory(size, memory);
                  -
                  - -

                  The input layer to the memory layer should always have the same size as the memory size. -The memory layer will output a total of size * memory values.

                  -
                  -

                  This page is incomplete. There is no description on the functions you can use -on this instance yet. Feel free to add the info (check out src/layer.js)

                  -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/architecture/network/index.html b/node_modules/neataptic/docs/docs/architecture/network/index.html deleted file mode 100644 index 8b8b238..0000000 --- a/node_modules/neataptic/docs/docs/architecture/network/index.html +++ /dev/null @@ -1,546 +0,0 @@ - - - Neataptic.js - Network - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Network

                  -

                  Edit on Github

                  -
                  -

                  Networks are very easy to create. All you have to do is specify an input size and an output size.

                  -
                  // Network with 2 input neurons and 1 output neuron
                  -var myNetwork = new Network(2, 1);
                  -
                  -// If you want to create multi-layered networks
                  -var myNetwork = new architect.Perceptron(5, 20, 10, 5, 1);
                  -
                  - -

                  If you want to create more advanced networks, check out the 'Networks' tab on the left.

                  -

                  Functions

                  -

                  Check out the train and evolve functions on their separate pages!

                  -

                  - activate - Activates the network. It will activate all the nodes in activation order and produce an output.

                  -
                  -// Create a network
                  -var myNetwork = new Network(3, 2);
                  -
                  -myNetwork.activate([0.8, 1, 0.21]); // gives: [0.49, 0.51]
                  -
                  - -

                  -

                  - noTraceActivate - Activates the network. It will activate all the nodes in activation order and produce an output. - Does not calculate traces, so backpropagation is not possible afterwards. That makes - it faster than the regular activate function.

                  -
                  -// Create a network
                  -var myNetwork = new Network(3, 2);
                  -
                  -myNetwork.noTraceActivate([0.8, 1, 0.21]); // gives: [0.49, 0.51]
                  -
                  - -

                  -

                  - propagate - This function allows you to teach the network. If you want to do more complex - training, use the network.train() function. The arguments for - this function are:

                  -
                  -myNetwork.propagate(rate, momentum, update, target);
                  -
                  - -

                  Where target is optional. The default value of momentum is 0. Read more about -momentum on the regularization page. If you run -propagation without setting update to true, then the weights won't update. So if -you run propagate 3x with update: false, and then 1x with update: true then -the weights will be updated after the last propagation, but the deltaweights of -the first 3 propagation will be included too.

                  -
                  -var myNetwork = new Network(1,1);
                  -
                  -// This trains the network to function as a NOT gate
                  -for(var i = 0; i < 1000; i++){
                  -  network.activate([0]);  
                  -  network.propagate(0.2, 0, true, [1]);
                  -
                  -  network.activate([1]);
                  -  network.propagate(0.3, 0, true, [0]);
                  -}
                  -
                  - -

                  The above example teaches the network to output [1] when input [0] is given and the other way around. Main usage:

                  -
                  -network.activate(input);
                  -network.propagate(learning_rate, momentum, update_weights, desired_output);
                  -
                  - -

                  -

                  - merge - The merge functions takes two networks, the output size of network1 should be the same size as the input of network2. Merging will always be one to one to conserve the purpose of the networks. Usage:

                  -
                  -var XOR = architect.Perceptron(2,4,1); // assume this is a trained XOR
                  -var NOT = architect.Perceptron(1,2,1); // assume this is a trained NOT
                  -
                  -// combining these will create an XNOR
                  -var XNOR = Network.merge(XOR, NOT);
                  -
                  - -

                  -

                  - connect - Connects two nodes in the network:

                  -
                  -myNetwork.connect(myNetwork.nodes[4], myNetwork.nodes[5]);
                  -
                  - -

                  -

                  - remove - Removes a node from a network, all its connections will be redirected. If it gates a connection, the gate will be removed.

                  -
                  -myNetwork = new architect.Perceptron(1,4,1);
                  -
                  -// Remove a node
                  -myNetwork.remove(myNetwork.nodes[2]);
                  -
                  - -

                  -

                  - disconnect - Disconnects two nodes in the network:

                  -
                  -myNetwork.disconnect(myNetwork.nodes[4], myNetwork.nodes[5]);
                  -// now node 4 does not have an effect on the output of node 5 anymore
                  -
                  - -

                  -

                  - gate - Makes a network node gate a connection:

                  -
                  -myNetwork.gate(myNetwork.nodes[1], myNetwork.connections[5]
                  -
                  - -

                  Now the weight of connection 5 is multiplied with the activation of node 1! -

                  -

                  - ungate - Removes a gate from a connection:

                  -
                  -myNetwork = new architect.Perceptron(1, 4, 2);
                  -
                  -// Gate a connection
                  -myNetwork.gate(myNetwork.nodes[2], myNetwork.connections[5]);
                  -
                  -// Remove the gate from the connection
                  -myNetwork.ungate(myNetwork.connections[5]);
                  -
                  - -

                  -

                  - mutate - Mutates the network. See mutation methods. -

                  -

                  - serialize - Serializes the network to 3 Float64Arrays. Used for transferring - networks to other threads fast. -

                  -

                  - toJSON/fromJSON - Networks can be stored as JSON's and then restored back:

                  -
                  -var exported = myNetwork.toJSON();
                  -var imported = Network.fromJSON(exported);
                  -
                  - -

                  imported will be a new instance of Network that is an exact clone of myNetwork. -

                  -

                  - standalone - Networks can be used in Javascript without the need of the Neataptic library, - this function will transform your network into a function accompanied by arrays.

                  -
                  -var myNetwork = new architect.Perceptron(2,4,1);
                  -myNetwork.activate([0,1]); // [0.24775789809]
                  -
                  -// a string
                  -var standalone = myNetwork.standalone();
                  -
                  -// turns your network into an 'activate' function
                  -eval(standalone);
                  -
                  -// calls the standalone function
                  -activate([0,1]);// [0.24775789809]
                  -
                  - -

                  The reason an eval is being called is because the standalone can't be a simply -a function, it needs some kind of global memory. You can easily copy and paste the -result of standalone in any JS file and run the activate function!

                  -

                  Note that this is still in development, so for complex networks, it might not be -precise.

                  -

                  -

                  - crossOver - Creates a new 'baby' network from two parent networks. Networks are not required to have the same size, however input and output size should be the same!

                  -
                  -// Initialise two parent networks
                  -var network1 = new architect.Perceptron(2, 4, 3);
                  -var network2 = new architect.Perceptron(2, 4, 5, 3);
                  -
                  -// Produce an offspring
                  -var network3 = Network.crossOver(network1, network2);
                  -
                  - -

                  -

                  - set - Sets the properties of all nodes in the network to the given values, e.g.:

                  -
                  -var network = new architect.Random(4, 4, 1);
                  -
                  -// All nodes in 'network' now have a bias of 1
                  -network.set({bias: 1});
                  -
                  - -

                  -

                  - clear - Clears the context of the network. Useful for predicting timeseries with LSTM's. clear() has little to no effecton regular NN, use on RNN's! -

                  -

                  Properties

                  -

                  Each network only has a small number of properties.

                  -

                  - input - Input size of the network -

                  -

                  - output - Output size of the network -

                  -

                  - nodes - Array of nodes -

                  -

                  - connections - Array of connections -

                  -

                  - gates - Array of gated connections -

                  -

                  - selfconns - Array of self connections -

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/architecture/node/index.html b/node_modules/neataptic/docs/docs/architecture/node/index.html deleted file mode 100644 index 7ffd470..0000000 --- a/node_modules/neataptic/docs/docs/architecture/node/index.html +++ /dev/null @@ -1,509 +0,0 @@ - - - Neataptic.js - Node - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Node

                  -

                  Edit on Github

                  -
                  -

                  Nodes are the key to neural networks. They provide the non-linearity in the output. A node can be created as follows:

                  -
                  var node = new Node();
                  -
                  - -

                  Node properties:

                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  Propertycontains
                  biasthe bias when calculating state
                  squashactivation function
                  type'input', 'hidden' or 'output', should not be used manually (setting to 'constant' will disable bias/weight changes)
                  activationactivation value
                  connectionsdictionary of in and out connections
                  oldstores the previous activation
                  statestores the state (before being squashed)
                  -

                  activate

                  -

                  Actives the node. Calculates the state from all the input connections, adds the bias, and 'squashes' it.

                  -
                  var node = new Node();
                  -node.activate(); // 0.4923128591923
                  -
                  - -

                  noTraceActivate

                  -

                  Actives the node. Calculates the state from all the input connections, adds the bias, and 'squashes' it. -Does not calculate traces, so this can't be used to backpropagate afterwards. -That's also why it's quite a bit faster than regular activate.

                  -
                  var node = new Node();
                  -node.noTraceActivate(); // 0.4923128591923
                  -
                  - -

                  propagate

                  -

                  After an activation, you can teach the node what should have been the correct -output (a.k.a. train). This is done by backpropagating the error. To use the -propagate method you have to provide a learning rate, and a target value -(float between 0 and 1).

                  -

                  The arguments you can pass on are as follows:

                  -
                  myNode.propagate(learningRate, momentum, update, target);
                  -
                  - -

                  The target argument is optional. The default value of momentum is 0. Read more -about momentum on the regularization page. If you run -propagation without setting update to true, then the weights won't update. So if -you run propagate 3x with update: false, and then 1x with update: true then -the weights will be updated after the last propagation, but the deltaweights of -the first 3 propagation will be included too. For example, this is how you can -train node B to activate 0 when node A activates 1:

                  -
                  var A = new Node();
                  -var B = new Node('output');
                  -A.connect(B);
                  -
                  -var learningRate = .3;
                  -var momentum = 0;
                  -
                  -for(var i = 0; i < 20000; i++)
                  -{
                  -  // when A activates 1
                  -  A.activate(1);
                  -
                  -  // train B to activate 0
                  -  B.activate();
                  -  B.propagate(learningRate, momentum, true, 0);
                  -}
                  -
                  -// test it
                  -A.activate(1);
                  -B.activate(); // 0.006540565760853365
                  -
                  - -

                  connect

                  -

                  A node can project a connection to another node or group (i.e. connect node A with node B). Here is how it's done:

                  -
                  var A = new Node();
                  -var B = new Node();
                  -A.connect(B); // A now projects a connection to B
                  -
                  -// But you can also connect nodes to groups
                  -var C = new Group(4);
                  -
                  -B.connect(C); // B now projects a connection to all nodes in C
                  -
                  - -

                  A neuron can also connect to itself, creating a selfconnection:

                  -
                  var A = new Node();
                  -A.connect(A); // A now connects to itself
                  -
                  - -

                  disconnect

                  -

                  Removes the projected connection from this node to the given node.

                  -
                  var A = new Node();
                  -var B = new Node();
                  -A.connect(B); // A now projects a connection to B
                  -
                  -A.disconnect(B); // no connection between A and B anymore
                  -
                  - -

                  If the nodes project a connection to each other, you can also disconnect both connections at once:

                  -
                  var A = new Node();
                  -var B = new Node();
                  -A.connect(B); // A now projects a connection to B
                  -B.connect(A); // B now projects a connection to A
                  -
                  -
                  -// A.disconnect(B)  only disconnects A to B, so use
                  -A.disconnect(B, true); // or B.disconnect(A, true)
                  -
                  - -

                  gate

                  -

                  Neurons can gate connections. This means that the activation value of a neuron has influence on the value transported through a connection. You can either give an array of connections or just a connection as an argument.

                  -
                  var A = new Node();
                  -var B = new Node();
                  -var C = new Node();
                  -
                  -var connections = A.connect(B);
                  -
                  -// Now gate the connection(s)
                  -C.gate(connections);
                  -
                  - -

                  Now the weight of the connection from A to B will always be multiplied by the activation of node C.

                  -

                  ungate

                  -

                  You can also remove a gate from a connection.

                  -
                  var A = new Node();
                  -var B = new Node();
                  -var C = new Node();
                  -
                  -var connections = A.connect(B);
                  -
                  -// Now gate the connection(s)
                  -C.gate(connections);
                  -
                  -// Now ungate those connections
                  -C.ungate(connections);
                  -
                  - -

                  isProjectingTo

                  -

                  Checks if the node is projecting a connection to another neuron.

                  -
                  var A = new Node();
                  -var B = new Node();
                  -var C = new Node();
                  -A.connect(B);
                  -B.connect(C);
                  -
                  -A.isProjectingTo(B); // true
                  -A.isProjectingTo(C); // false
                  -
                  - -

                  isProjectedBy

                  -

                  Checks if the node is projected by another node.

                  -
                  var A = new Node();
                  -var B = new Node();
                  -var C = new Node();
                  -A.connect(B);
                  -B.connect(C);
                  -
                  -A.isProjectedBy(C); // false
                  -B.isProjectedBy(A); // true
                  -
                  - -

                  toJSON/fromJSON

                  -

                  Nodes can be stored as JSON's and then restored back:

                  -
                  var exported = myNode.toJSON();
                  -var imported = Network.fromJSON(exported);
                  -
                  - -

                  imported will be a new instance of Node that is an exact clone of myNode.

                  -

                  clear

                  -

                  Clears the context of the node. Useful for predicting timeseries with LSTM's.

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/builtins/builtins/index.html b/node_modules/neataptic/docs/docs/builtins/builtins/index.html deleted file mode 100644 index 14c761e..0000000 --- a/node_modules/neataptic/docs/docs/builtins/builtins/index.html +++ /dev/null @@ -1,322 +0,0 @@ - - - Neataptic.js - Built-in networks - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Built-in networks

                  -

                  Edit on Github

                  -
                  -

                  If you are unfamiliar with building networks layer by layer, you can use the -preconfigured networks. These networks will also be built layer by layer behind -the screens, but for the user they are all a simple one line function. At this -moment, Neataptic offers 6 preconfigured networks.

                  - -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/builtins/gru/index.html b/node_modules/neataptic/docs/docs/builtins/gru/index.html deleted file mode 100644 index f682d1b..0000000 --- a/node_modules/neataptic/docs/docs/builtins/gru/index.html +++ /dev/null @@ -1,353 +0,0 @@ - - - Neataptic.js - GRU - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  GRU

                  -

                  Edit on Github

                  -
                  -
                  -

                  Please be warned: GRU is still being tested, it might not always work for your dataset.

                  -
                  -

                  The Gated Recurrent Unit network is very similar to the LSTM network. GRU networks have óne gate less and no selfconnections. Similarly to LSTM's, GRU's are well-suited to classify, process and predict time series when there are very long time lags of unknown size between important events.

                  -

                  -

                  To use this architecture you have to set at least one input node, one gated recurrent unit assembly, and an output node. The gated recurrent unit assembly consists of seven nodes: input, update gate, inverse update gate, reset gate, memorycell, output and previous output memory.

                  -
                  var myLSTM = new architect.GRU(2,6,1);
                  -
                  - -

                  Also you can set many layers of gated recurrent units:

                  -
                  var myLSTM = new architect.GRU(2, 4, 4, 4, 1);
                  -
                  - -

                  The above network has 3 hidden layers, with 4 GRU assemblies each. It has two inputs and óne output.

                  -

                  While training sequences or timeseries prediction to a GRU, make sure you set the clear option to true while training. Additionally, through trial and error, I have discovered that using a lower rate than normal works best for GRU networks (e.g. 0.1 instead of 0.3).

                  -

                  This is an example of training the sequence XOR gate to a a GRU network:

                  -
                  var trainingSet = [
                  -  { input: [0], output: [0]},
                  -  { input: [1], output: [1]},
                  -  { input: [1], output: [0]},
                  -  { input: [0], output: [1]},
                  -  { input: [0], output: [0]}
                  -];
                  -
                  -var network = new architect.GRU(1,1,1);
                  -
                  -// Train a sequence: 00100100..
                  -network.train(trainingSet, {
                  -  log: 1,
                  -  rate: 0.1,
                  -  error: 0.005,
                  -  iterations: 3000,
                  -  clear: true
                  -});
                  -
                  - -

                  Run it here yourself!

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/builtins/hopfield/index.html b/node_modules/neataptic/docs/docs/builtins/hopfield/index.html deleted file mode 100644 index 4254e68..0000000 --- a/node_modules/neataptic/docs/docs/builtins/hopfield/index.html +++ /dev/null @@ -1,333 +0,0 @@ - - - Neataptic.js - Hopfield - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Hopfield

                  -

                  Edit on Github

                  -
                  -
                  -

                  This network might be removed soon

                  -
                  -

                  The hopfield architecture is excellent for remembering patterns. Given an input, it will output the most similar pattern it was trained. The output will always be binary, due to the usage of the Activation.STEP function.

                  -
                  var network = architect.Hopfield(10);
                  -var trainingSet = [
                  -  { input: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1], output: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1] },
                  -  { input: [1, 1, 1, 1, 1, 0, 0, 0, 0, 0], output: [1, 1, 1, 1, 1, 0, 0, 0, 0, 0] }
                  -];
                  -
                  -network.train(trainingSet);
                  -
                  -network.activate([0,1,0,1,0,1,0,1,1,1]); // [0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
                  -network.activate([1,1,1,1,1,0,0,1,0,0]); // [1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
                  -
                  - -

                  The input for the training set must always be the same as the output.

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/builtins/lstm/index.html b/node_modules/neataptic/docs/docs/builtins/lstm/index.html deleted file mode 100644 index 40c4222..0000000 --- a/node_modules/neataptic/docs/docs/builtins/lstm/index.html +++ /dev/null @@ -1,341 +0,0 @@ - - - Neataptic.js - LSTM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  LSTM

                  -

                  Edit on Github

                  -
                  -

                  The long short-term memory is an architecture well-suited to learn from experience to classify, process and predict time series when there are very long time lags of unknown size between important events.

                  -

                  Long short-term memory cell

                  -

                  To use this architecture you have to set at least one input node, one memory block assembly (consisting of four nodes: input gate, memory cell, forget gate and output gate), and an output node.

                  -
                  var myLSTM = new architect.LSTM(2,6,1);
                  -
                  - -

                  Also you can set many layers of memory blocks:

                  -
                  var myLSTM = new architect.LSTM(2, 4, 4, 4, 1);
                  -
                  - -

                  That LSTM network has 3 memory block assemblies, with 4 memory cells each, and their own input gates, memory cells, forget gates and output gates.

                  -

                  You can pass options if desired like so:

                  -
                  var options = {
                  -  memoryToMemory: false,    // default is false
                  -  outputToMemory: false,    // default is false
                  -  outputToGates: false,     // default is false
                  -  inputToOutput: true,      // default is true
                  -  inputToDeep: true         // default is true
                  -};
                  -
                  -var myLSTM = new architect.LSTM(2, 4, 4, 4, 1, options);
                  -
                  - -

                  While training sequences or timeseries prediction to a LSTM, make sure you set the clear option to true while training. See an example of sequence prediction here.

                  -

                  This is an example of character-by-character typing by an LSTM: JSFiddle

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/builtins/narx/index.html b/node_modules/neataptic/docs/docs/builtins/narx/index.html deleted file mode 100644 index 486b189..0000000 --- a/node_modules/neataptic/docs/docs/builtins/narx/index.html +++ /dev/null @@ -1,354 +0,0 @@ - - - Neataptic.js - NARX - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  NARX

                  -

                  Edit on Github

                  -
                  -

                  Just like LSTM's, NARX networks are very good at timeseries prediction. That is because they use previous inputs and their corresponding output values as the next input to the hidden layer.

                  -

                  -

                  The constructor looks like this:

                  -
                  var network = new architect.NARX(inputSize, hiddenLayers, outputSize, previousInput, previousOutput);
                  -
                  - -

                  A quick explanation of each argument:

                  -
                    -
                  • inputSize: the amount of input nodes
                  • -
                  • hiddenLayers: an array containing hidden layer sizes, e.g. [10,20,10]. If only one hidden layer, can be a number (of nodes)
                  • -
                  • outputSize: the amount of output nodes
                  • -
                  • previousInput: the amount of previous inputs you want it to remember
                  • -
                  • previousOutput: the amount of previous outputs you want it to remember
                  • -
                  -

                  Example:

                  -
                  var narx = new architect.NARX(1, 5, 1, 3, 3);
                  -
                  -// Train the XOR gate (in sequence!)
                  -var trainingData = [
                  -  { input: [0], output: [0] },
                  -  { input: [0], output: [0] },
                  -  { input: [0], output: [1] },
                  -  { input: [1], output: [0] },
                  -  { input: [0], output: [0] },
                  -  { input: [0], output: [0] },
                  -  { input: [0], output: [1] },
                  -];
                  -
                  -narx.train(trainingData, {
                  -  log: 1,
                  -  iterations: 3000,
                  -  error: 0.03,
                  -  rate: 0.05
                  -});
                  -
                  - -

                  Run it here

                  -

                  The NARX network type has 'constant' nodes. These nodes won't affect the weight of their incoming connections and their bias will never change. Please do note that mutation CAN change all of these.

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/builtins/perceptron/index.html b/node_modules/neataptic/docs/docs/builtins/perceptron/index.html deleted file mode 100644 index 380770a..0000000 --- a/node_modules/neataptic/docs/docs/builtins/perceptron/index.html +++ /dev/null @@ -1,325 +0,0 @@ - - - Neataptic.js - Perceptron - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Perceptron

                  -

                  Edit on Github

                  -
                  -

                  This architecture allows you to create multilayer perceptrons, also known as feed-forward neural networks. They consist of a sequence of layers, each fully connected to the next one.

                  -

                  multilayer perceptron

                  -

                  You have to provide a minimum of 3 layers (input, hidden and output), but you can use as many hidden layers as you wish. This is a Perceptron with 2 neurons in the input layer, 3 neurons in the hidden layer, and 1 neuron in the output layer:

                  -
                  var myPerceptron = new architect.Perceptron(2,3,1);
                  -
                  - -

                  And this is a deep multilayer perceptron with 2 neurons in the input layer, 4 hidden layers with 10 neurons each, and 1 neuron in the output layer

                  -
                  var myPerceptron = new architect.Perceptron(2, 10, 10, 10, 10, 1);
                  -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/builtins/random/index.html b/node_modules/neataptic/docs/docs/builtins/random/index.html deleted file mode 100644 index b21fc98..0000000 --- a/node_modules/neataptic/docs/docs/builtins/random/index.html +++ /dev/null @@ -1,342 +0,0 @@ - - - Neataptic.js - Random - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Random

                  -

                  Edit on Github

                  -
                  -

                  A random network is similar to a liquid network. This network will start of with a given pool of nodes, and will then create random connections between them. This network is really only useful for the initialization of the population for a genetic algorithm.

                  -
                  new architect.Random(input_size, hidden_size, output_size, options);
                  -
                  - -
                    -
                  • input_size : amount of input nodes
                  • -
                  • hidden_size : amount of nodes inbetween input and output
                  • -
                  • output_size : amount of output nodes
                  • -
                  -

                  Options: - connections : amount of connections (default is 2 * hidden_size, should always be bigger than hidden_size!) - backconnections : amount of recurrent connections (default is 0) - selfconnections : amount of selfconnections (default is 0) - gates : amount of gates (default is 0)

                  -

                  For example:

                  -
                  var network = architect.Random(1, 20, 2, {
                  -  connections: 40,
                  -  gates: 4,
                  -  selfconnections: 4
                  -});
                  -
                  -drawGraph(network.graph(1000, 800), '.svg');
                  -
                  - -

                  will produce:

                  -

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/important/evolve/index.html b/node_modules/neataptic/docs/docs/important/evolve/index.html deleted file mode 100644 index 2fe28b1..0000000 --- a/node_modules/neataptic/docs/docs/important/evolve/index.html +++ /dev/null @@ -1,417 +0,0 @@ - - - Neataptic.js - Evolve - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Evolve

                  -

                  Edit on Github

                  -
                  -

                  The evolve function will evolve the network to conform the given training set. If you want to perform neuro-evolution on problems without a training set, check out the NEAT wiki page. This function may not always be successful, so always specify a number of iterations for it too maximally run.

                  -

                  View a whole bunch of neuroevolution algorithms set up with Neataptic here.

                  -

                  Constructor

                  -

                  Initiating the evolution of your neural network is easy:

                  -
                  await myNetwork.evolve(trainingSet, options);
                  -
                  - -

                  Please note that await is used as evolve is an async function. Thus, you -need to wrap these statements in an async function.

                  -

                  Training set

                  -

                  Where trainingSet is your training set. An example is coming up ahead. An example -of a training set would be:

                  -
                  // XOR training set
                  -var trainingSet = [
                  -  { input: [0,0], output: [0] },
                  -  { input: [0,1], output: [1] },
                  -  { input: [1,0], output: [1] },
                  -  { input: [1,1], output: [0] }
                  -];
                  -
                  - -

                  Options

                  -

                  There are a lot of options, here are the basic options:

                  -
                    -
                  • cost - Specify the cost function for the evolution, this tells a genome in the population how well it's performing. Default: methods.cost.MSE (recommended).
                  • -
                  • amount- Set the amount of times to test the trainingset on a genome each generation. Useful for timeseries. Do not use for regular feedfoward problems. Default is 1.
                  • -
                  • -

                    growth - Set the penalty you want to give for large networks. The penalty get's calculated as follows: penalty = (genome.nodes.length + genome.connectoins.length + genome.gates.length) * growth; -This penalty will get added on top of the error. Your growth should be a very small number, the default value is 0.0001

                    -
                  • -
                  • -

                    iterations - Set the maximum amount of iterations/generations for the algorithm to run. Always specify this, as the algorithm will not always converge.

                    -
                  • -
                  • error - Set the target error. The algorithm will stop once this target error has been reached. The default value is 0.005.
                  • -
                  • log - If set to n, will output every n iterations (log : 1 will log every iteration)
                  • -
                  • schedule - You can schedule tasks to happen every n iterations. An example of usage is schedule : { function: function(){console.log(Date.now)}, iterations: 5}. This will log the time every 5 iterations. This option allows for complex scheduled tasks during evolution.
                  • -
                  • clear - If set to true, will clear the network after every activation. This is useful for evolving recurrent networks, more importantly for timeseries prediction. Default: false
                  • -
                  • threads - Specify the amount of threads to use. Default value is the amount of cores in your CPU. Set to 1 if you are evolving on a small dataset.
                  • -
                  -

                  Please note that you can also specify any of the options that are specified on -the neat page.

                  -

                  An example of options would be:

                  -
                  var options = {
                  -  mutation: methods.mutation.ALL,
                  -  mutationRate: 0.4,
                  -  clear: true,
                  -  cost: methods.cost.MSE,
                  -  error: 0.03,
                  -  log: 1,
                  -  iterations: 1000
                  -};
                  -
                  - -

                  If you want to use the default options, you can either pass an empty object or -just dismiss the whole second argument:

                  -
                  await myNetwork.evolve(trainingSet, {});
                  -
                  -// or
                  -
                  -await myNetwork.evolve(trainingSet);
                  -
                  - -

                  The default value will be used for any option that is not explicitly provided -in the options object.

                  -

                  Result

                  -

                  This function will output an object containing the final error, amount of iterations, time and the evolved network:

                  -
                  return results = {
                  -  error: mse,
                  -  generations: neat.generation,
                  -  time: Date.now() - start,
                  -  evolved: fittest
                  -};
                  -
                  - -

                  Examples

                  -

                  - XOR - Activates the network. It will activate all the nodes in activation order and produce an output. -
                  -async function execute () {
                  -  var network = new Network(2,1);

                  -

                  // XOR dataset - var trainingSet = [ - { input: [0,0], output: [0] }, - { input: [0,1], output: [1] }, - { input: [1,0], output: [1] }, - { input: [1,1], output: [0] } - ];

                  -

                  await network.evolve(trainingSet, { - mutation: methods.mutation.FFW, - equal: true, - elitism: 5, - mutationRate: 0.5 - });

                  -

                  network.activate([0,0]); // 0.2413 - network.activate([0,1]); // 1.0000 - network.activate([1,0]); // 0.7663 - network.activate([1,1]); // -0.008 -}

                  -

                  execute();

                  -

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/important/important/index.html b/node_modules/neataptic/docs/docs/important/important/index.html deleted file mode 100644 index fd24a72..0000000 --- a/node_modules/neataptic/docs/docs/important/important/index.html +++ /dev/null @@ -1,320 +0,0 @@ - - - Neataptic.js - Important functions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Important functions

                  -

                  Edit on Github

                  -
                  - -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/important/train/index.html b/node_modules/neataptic/docs/docs/important/train/index.html deleted file mode 100644 index 1ace127..0000000 --- a/node_modules/neataptic/docs/docs/important/train/index.html +++ /dev/null @@ -1,413 +0,0 @@ - - - Neataptic.js - Train - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Train

                  -

                  Edit on Github

                  -
                  -

                  The train method allows you to train your network with given parameters. If this -documentation is too complicated, I recommend to check out the -training tutorial!

                  -

                  Constructor

                  -

                  Initiating the training process is similar to initiating the evolution process:

                  -
                  -myNetwork.train(trainingSet, options)
                  -
                  - -

                  Training set

                  -

                  Where set is an array containing objects in the following way: { input: [input(s)], output: [output(s)] }. So for example, this is how you would train an XOR:

                  -
                  -var network = new architect.Perceptron(2,4,1);
                  -
                  -// Train the XOR gate
                  -network.train([{ input: [0,0], output: [0] },
                  -               { input: [0,1], output: [1] },
                  -               { input: [1,0], output: [1] },
                  -               { input: [1,1], output: [0] }]);
                  -
                  -network.activate([0,1]); // 0.9824...
                  -
                  - -

                  Options

                  -

                  Options allow you to finetune the training process:

                  -
                    -
                  • log - If set to n, will output the training status every n iterations (log : 1 will log every iteration)
                  • -
                  • error - The target error to reach, once the network falls below this error, the process is stopped. Default: 0.03
                  • -
                  • cost - The cost function to use. See cost methods. Default: methods.cost.MSE
                  • -
                  • rate - Sets the learning rate of the backpropagation process. Default: 0.3.
                  • -
                  • dropout - Sets the dropout of the hidden network nodes. Read more about it on the regularization page. Default: 0.
                  • -
                  • shuffle - When set to true, will shuffle the training data every iteration. A good option to use if your network is performing less in cross validation than in the real training set. Default: false
                  • -
                  • iterations - Sets the amount of iterations the process will maximally run, even when the target error has not been reached. Default: NaN
                  • -
                  • schedule - You can schedule tasks to happen every n iterations. An example of usage is schedule : { function: function(data){console.log(Date.now, data.error)}, iterations: 5}. This will log the time and error every 5 iterations. This option allows for complex scheduled tasks during training.
                  • -
                  • clear - If set to true, will clear the network after every activation. This is useful for training LSTM's, more importantly for timeseries prediction. Default: false
                  • -
                  • momentum - Sets the momentum of the weight change. More info here. Default: 0
                  • -
                  • ratePolicy - Sets the rate policy for your training. This allows your rate to be dynamic, see the rate policies page. Default: methods.rate.FIXED()
                  • -
                  • batchSize - Sets the (mini-) batch size of your training. Default: 1 (online training)
                  • -
                  -

                  If you want to use the default options, you can either pass an empty object or -just dismiss the whole second argument:

                  -
                  myNetwork.evolve(trainingSet, {});
                  -
                  -// or
                  -
                  -myNetwork.evolve(trainingSet);
                  -
                  - -

                  The default value will be used for any option that is not explicitly provided -in the options object.

                  -

                  Example

                  -

                  So the following setup will train until the error of 0.0001 is reached or if the iterations hit 1000. It will log the status every iteration as well. The rate has been lowered to 0.2.

                  -
                  var network = new architect.Perceptron(2,4,1);
                  -
                  -var trainingSet = [
                  -  { input: [0,0], output: [1] },
                  -  { input: [0,1], output: [0] },
                  -  { input: [1,0], output: [0] },
                  -  { input: [1,1], output: [1] }
                  -];
                  -
                  -// Train the XNOR gate
                  -network.train(trainingSet, {
                  -  log: 1,
                  -  iterations: 1000,
                  -  error: 0.0001,
                  -  rate: 0.2
                  -});
                  -
                  - -

                  Cross-validation

                  -

                  The last option is the crossValidate option, which will validate if the network also performs well enough on a non-trained part of the given set. Options:

                  -
                    -
                  • crossValidate.testSize - Sets the amount of test cases that should be assigned to cross validation. If set to 0.4, 40% of the given set will be used for cross validation.
                  • -
                  • crossValidate.testError - Sets the target error of the validation set.
                  • -
                  -

                  So an example of cross validation would be:

                  -
                  var network = new architect.Perceptron(2,4,1);
                  -
                  -var trainingSet = [
                  -  { input: [0,0], output: [1] },
                  -  { input: [0,1], output: [0] },
                  -  { input: [1,0], output: [0] },
                  -  { input: [1,1], output: [1] }
                  -];
                  -
                  -// Train the XNOR gate
                  -network.train(trainingSet, {
                  -  crossValidate :
                  -    {
                  -      testSize: 0.4,
                  -      testError: 0.02
                  -    }
                  -});
                  -
                  - -

                  PS: don't use cross validation for small sets, this is just an example!

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/index.html b/node_modules/neataptic/docs/docs/index.html deleted file mode 100644 index e88e928..0000000 --- a/node_modules/neataptic/docs/docs/index.html +++ /dev/null @@ -1,322 +0,0 @@ - - - Neataptic.js - Docs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Docs

                  -

                  Edit on Github

                  -
                  -

                  Welcome to the documentation of Neataptic! If you are a rookie with neural networks: -check out any of the tutorials on the left to get started. If you want more -information about a certain part of Neataptic, it most probably is also in the -menu on the left. If it isn't, feel free to let me know by creating an issue.

                  -

                  If you want to implement a genetic neural network algorithm, but don't know how, -feel free to contact me at wagenaartje@protonmail.com!

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/methods/activation/index.html b/node_modules/neataptic/docs/docs/methods/activation/index.html deleted file mode 100644 index c220f3c..0000000 --- a/node_modules/neataptic/docs/docs/methods/activation/index.html +++ /dev/null @@ -1,429 +0,0 @@ - - - Neataptic.js - Activation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Activation

                  -

                  Edit on Github

                  -
                  -

                  Activation functions determine what activation value neurons should get. Depending on your network's environment, choosing a suitable activation function can have a positive impact on the learning ability of the network.

                  -

                  Methods

                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  NameGraphEquationDerivative
                  LOGISTIC$ f(x) = \frac{1}{1+e^{-x}} $$ f'(x) = f(x)(1 - f(x)) $
                  TANH$ f(x) = tanh(x) = \frac{2}{1+e^{-2x}} - 1 $$ f'(x) = 1 - f(x)^2 $
                  RELU$ f(x) = \begin{cases} 0 & \text{if} & x \lt 0 \\ x & \text{if} & x \ge 0 \end{cases} $$ f'(x) = \begin{cases} 0 & \text{if} & x \lt 0 \\ 1 & \text{if} & x \ge 0 \end{cases} $
                  IDENTITY$ f(x) = x $$ f'(x) = 1 $
                  STEP$ f(x) = \begin{cases} 0 & \text{if} & x \lt 0 \\ 1 & \text{if} & x \ge 0 \end{cases} $$ f'(x) = \begin{cases} 0 & \text{if} & x \neq 0 \\ ? & \text{if} & x = 0 \end{cases} $
                  SOFTSIGN$ f(x) = \frac{x}{1+\left\lvert x \right\rvert} $$ f'(x) = \frac{x}{{(1+\left\lvert x \right\rvert)}^2} $
                  SINUSOID$ f(x) = sin(x) $$ f'(x) = cos(x) $
                  GAUSSIAN$ f(x) = e^{-x^2} $$ f'(x) = -2xe^{-x^2} $
                  BENT_IDENTITY$ f(x) = \frac{\sqrt{x^2+1} - 1}{2} + x$$ f'(x) = \frac{ x }{2\sqrt{x^2+1}} + 1 $
                  BIPOLAR$ f(x) = \begin{cases} -1 & \text{if} & x \le 0 \\ 1 & \text{if} & x \gt 0 \end{cases} $$ f'(x) = 0 $
                  BIPOLAR_SIGMOID$ f(x) = \frac{2}{1+e^{-x}} - 1$$f'(x) = \frac{(1 + f(x))(1 - f(x))}{2} $
                  HARD_TANH$ f(x) = \text{max}(-1, \text{min}(1, x)) $$ f'(x) = \begin{cases} 1 & \text{if} & x \gt -1 & \text{and} & x \lt 1 \\ 0 & \text{if} & x \le -1 & \text{or} & x \ge 1 \end{cases} $
                  ABSOLUTE1$ f(x) = \left\lvert x \right\rvert $$ f'(x) = \begin{cases} -1 & \text{if} & x \lt 0 \\ 1 & \text{if} & x \ge 0 \end{cases} $
                  SELU$ f(x) = \lambda \begin{cases} x & \text{if} & x \gt 0 \\ \alpha e^x - \alpha & \text{if} & x \le 0 \end{cases} $$ f'(x) = \begin{cases} \lambda & \text{if} & x \gt 0 \\ \alpha e^x & \text{if} & x \le 0 \end{cases} $
                  INVERSE$ f(x) = 1 - x $$ f'(x) = -1 $
                  -

                  1 avoid using this activation function on a node with a selfconnection

                  -

                  Usage

                  -

                  By default, a neuron uses a Logistic Sigmoid as its squashing/activation function. You can change that property the following way:

                  -
                  var A = new Node();
                  -A.squash = methods.activation.<ACTIVATION_FUNCTION>;
                  -
                  -// eg.
                  -A.squash = methods.activation.SINUSOID;
                  -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/methods/cost/index.html b/node_modules/neataptic/docs/docs/methods/cost/index.html deleted file mode 100644 index 2b20e58..0000000 --- a/node_modules/neataptic/docs/docs/methods/cost/index.html +++ /dev/null @@ -1,374 +0,0 @@ - - - Neataptic.js - Cost - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Cost

                  -

                  Edit on Github

                  -
                  -

                  Cost functions -play an important role in neural networks. They give neural networks an indication -of 'how wrong' they are; a.k.a. how far they are from the desired output. But -also in fitness functions, cost functions play an important role.

                  -

                  Methods

                  -

                  At the moment, there are 7 built-in mutation methods (all for networks):

                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  NameFunction
                  methods.cost.CROSS_ENTROPY
                  methods.cost.MSE
                  methods.cost.BINARY
                  methods.cost.MAE
                  methods.cost.MAPE
                  methods.cost.MSLEnone
                  methods.cost.HINGE
                  -

                  Usage

                  -

                  Before experimenting with any of the loss functions, note that not every loss -function might 'work' for your network. Some networks have nodes with activation -functions that can have negative values; this will create some weird error values -with some cost methods. So if you don't know what you're doing: stick to any of -the first three cost methods!

                  -
                  myNetwork.train(trainingData, {
                  -  log: 1,
                  -  iterations: 500,
                  -  error: 0.03,
                  -  rate: 0.05,
                  -  cost: methods.cost.METHOD
                  -});
                  -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/methods/gating/index.html b/node_modules/neataptic/docs/docs/methods/gating/index.html deleted file mode 100644 index dcd293f..0000000 --- a/node_modules/neataptic/docs/docs/methods/gating/index.html +++ /dev/null @@ -1,326 +0,0 @@ - - - Neataptic.js - Gating - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Gating

                  -

                  Edit on Github

                  -
                  -

                  Gating is quite the interesting: it makes the weights in networks more dynamic, -by adapting them to their gating node. Read more about it here. -For specific implementation of gating, check out the Node, -Group and Network wikis!

                  -

                  There are 3 gating methods:

                  -
                    -
                  • methods.gating.OUTPUT every node in the gating group will gate (at least) 1 node in the emitting group and all its connections to the other, receiving group
                  • -
                  • methods.gating.INPUT every node in the gating group will gate (at least) 1 node in the receiving group and all its connections from the other, emitting group
                  • -
                  • methods.gating.SELF every node in the gating group will gate (at least) 1 self connection in the emitting/receiving group
                  • -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/methods/methods/index.html b/node_modules/neataptic/docs/docs/methods/methods/index.html deleted file mode 100644 index 60b4ae4..0000000 --- a/node_modules/neataptic/docs/docs/methods/methods/index.html +++ /dev/null @@ -1,321 +0,0 @@ - - - Neataptic.js - Methods - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Methods

                  -

                  Edit on Github

                  -
                  -

                  There are a lot of different methods for everything in Neataptic. This allows -the complete customization of your networks and algorithms. If you feel like any -method or function should be added, feel free to create an issue or a pull request.

                  - -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/methods/mutation/index.html b/node_modules/neataptic/docs/docs/methods/mutation/index.html deleted file mode 100644 index 8ce700b..0000000 --- a/node_modules/neataptic/docs/docs/methods/mutation/index.html +++ /dev/null @@ -1,471 +0,0 @@ - - - Neataptic.js - Mutation - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Mutation

                  -

                  Edit on Github

                  -
                  -

                  Mutation is an important aspect of genetic algorithms. Without any mutation, there is low probability of improvement. Mutating will change the bias or weights in neural networks, changing the output of the neural network. It can have a positive, but also a negative effect on the outcome of the neural network. However, one of the guidelines of genetic algorithms is too make sure that only the positive effects will be carried on.

                  -

                  Methods

                  -

                  At the moment, there are 7 built-in mutation methods (all for networks):

                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  NameAction
                  ADD_NODEAdds a node
                  SUB_NODERemoves node
                  ADD_CONNAdds a connection between two nodes
                  SUB_CONNRemoves a connection between two nodes
                  MOD_WEIGHTModifies the weight of a connection
                  MOD_BIASModifies the bias of a node
                  MOD_ACTIVATIONModifies the activation function of a node
                  ADD_SELF_CONNAdds a self-connection to a node
                  SUB_SELF_CONNRemoves a self-connection from a node
                  ADD_GATEMakes a node gate a connection
                  SUB_GATERemoves a gate from a connection
                  ADD_BACK_CONNAdds a recurrent connection
                  SUB_BACK_CONNRemoves a recurrent connection
                  SWAP_NODESSwaps the bias and squash function between two nodes
                  -

                  Usage

                  -

                  All of these mutation functions can be executed on any kind of network:

                  -
                  myNetwork.mutate(methods.mutation.<MUTATION_METHOD>);
                  -
                  -// eg.
                  -myNetwork.mutate(methods.mutation.ADD_NODE);
                  -
                  - -

                  And some on them on nodes (MOD_BIAS and MOD_ACTIVATION):

                  -
                  myNode.mutate(methods.mutation.<MUTATION_METHOD>);
                  -
                  -// eg.
                  -myNode.mutate(methods.mutation.MOD_BIAS);
                  -
                  - -

                  For network.evolve() and neat() options, specify a list of mutation methods as follows in the options (example):

                  -
                  network.evolve(trainingset, {
                  -  mutation: [methods.mutation.MOD_BIAS, methods.mutation.ADD_NODE]
                  -}
                  -
                  - -

                  You can also specify groups of methods:

                  -
                  network.evolve(trainingset, {
                  -  mutation: methods.mutation.ALL // all mutation methods
                  -}
                  -
                  -network.evolve(trainingset, {
                  -  mutation: methods.mutation.FFW// all feedforward mutation methods
                  -}
                  -
                  - -

                  Config

                  -

                  Some methods are configurable! You can change these config values as follows:

                  -
                  option = value;
                  -
                  -// eg.
                  -methods.mutation.MOD_ACTIVATION.mutateOutput = false;
                  -
                  - -

                  Or you can edit the methods/mutation.js file to change the default values.

                  -

                  -
                  methods.mutation.SUB_NODE.keep_gates // default: true
                  -
                  - -

                  When removing a node, you remove the connections and initialize new ones. Setting this option to true will make sure if the removed connections were gated, so will the new ones be.

                  -

                  -
                  methods.mutation.MOD_WEIGHT.min // default: -1
                  -methods.mutation.MOD_WEIGHT.max // default: 1
                  -
                  - -

                  Sets the upper and lower bounds of the modification of connection weights.

                  -

                  -
                  methods.mutation.MOD_BIAS.min // default: -1
                  -methods.mutation.MOD_BIAS.max // default: 1
                  -
                  - -

                  Sets the upper and lower bounds of the modification of neuron biases.

                  -

                  -
                  methods.mutation.MOD_ACTIVATION.mutateOutput // default: true
                  -methods.mutation.SWAP_NODES.mutateOutput     // default: true
                  -
                  - -

                  Disable this option if you want the have the activation function of the output neurons unchanged. Useful if you want to keep the output of your neural network normalized.

                  -

                  -
                  methods.mutation.MOD_ACTIVATION.allowed
                  -
                  -// default:
                  -[
                  -  activation.LOGISTIC,
                  -  activation.TANH,
                  -  activation.RELU,
                  -  activation.IDENTITY,
                  -  activation.STEP,
                  -  activation.SOFTSIGN,
                  -  activation.SINUSOID,
                  -  activation.GAUSSIAN,
                  -  activation.BENT_IDENTITY,
                  -  activation.BIPOLAR,
                  -  activation.BIPOLAR_SIGMOID,
                  -  activation.HARD_TANH,
                  -  activation.ABSOLUTE
                  -]
                  -
                  - -

                  This option allows you to specify which activation functions you want to allow in your neural network.

                  -

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/methods/rate/index.html b/node_modules/neataptic/docs/docs/methods/rate/index.html deleted file mode 100644 index 0becdf2..0000000 --- a/node_modules/neataptic/docs/docs/methods/rate/index.html +++ /dev/null @@ -1,367 +0,0 @@ - - - Neataptic.js - Rate - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Rate

                  -

                  Edit on Github

                  -
                  -

                  Rate policies allow the rate to be dynamic during the training of neural networks. -A few rate policies have been built-in, but it is very easy to create your own -as well. A detailed description of each rate policy is given below.

                  -

                  You can enable a rate policy during training like this:

                  -
                  network.train(trainingSet, {
                  -  rate: 0.3,
                  -  ratePolicy: methods.rate.METHOD(options),
                  -});
                  -
                  - -

                  methods.rate.FIXED

                  -

                  The default rate policy. Using this policy will make your rate static (it won't -change). You do not have to specify this rate policy during training per se.

                  -

                  methods.rate.STEP

                  -

                  The rate will 'step down' every n iterations.

                  -

                  step down rate

                  -

                  The main usage of this policy is:

                  -
                  methods.rate.STEP(gamma, stepSize)
                  -
                  -// default gamma: 0.9
                  -// default stepSize: 100
                  -
                  - -

                  A gamma of 0.9 means that every stepSize iterations, your current rate will -be reduced by 10%.

                  -

                  methods.rate.EXP

                  -

                  The rate will exponentially decrease.

                  -

                  exponential decrease

                  -

                  The main usage of this policy is:

                  -
                  methods.rate.EXP(gamma)
                  -
                  -// default gamma: 0.999
                  -
                  - -

                  The rate at a certain iteration is calculated as:

                  -
                  rate = baseRate * Math.pow(gamma, iteration)
                  -
                  - -

                  So a gamma of 0.999 will decrease the current rate by 0.1% every iteration

                  -

                  methods.rate.INV

                  -

                  reverse decay

                  -

                  The main usage of this policy is:

                  -
                  methods.rate.INV(gamma, power)
                  -
                  -// default gamma: 0.001
                  -// default power: 2
                  -
                  - -

                  The rate at a certain iteration is calculated as:

                  -
                  rate = baseRate * Math.pow(1 + gamma * iteration, -power)
                  -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/methods/regularization/index.html b/node_modules/neataptic/docs/docs/methods/regularization/index.html deleted file mode 100644 index 928dc36..0000000 --- a/node_modules/neataptic/docs/docs/methods/regularization/index.html +++ /dev/null @@ -1,356 +0,0 @@ - - - Neataptic.js - Regularization - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Regularization

                  -

                  Edit on Github

                  -
                  -

                  Regularization helps to keep weights and/or biases small in your network. Some -regularization methods also make sure that you are not overfitting your data.

                  -

                  Dropout

                  -

                  Enabling dropout will randomly set the activation of a neuron in a network to 0 -with a given probability.

                  -

                  -

                  Only use dropout when you are working with large datasets that may show some noise. -Dropout is a method that prevents overfitting, but it shouldn't work on datasets -like XOR or SINUS, as they don't have any noise. Dropout can only be used during -training:

                  -
                  myNetwork.train(myTrainingSet, {
                  -  error: 0.03,
                  -  iterations: 1000,
                  -  rate: 0.3,
                  -  dropout: 0.4 // if you're not sure, use 0.5
                  -});
                  -
                  - -

                  Setting the dropout to 0.4 means that 40% of the neurons will be dropped out -every training iteration. Please note that Neataptic has no layered network -architecture, so dropout applies to the complete hidden area.

                  -

                  Momentum

                  -

                  Momentum simply adds a fraction m of the previous weight update to the current one. -When the gradient keeps pointing in the same direction, this will increase the size -of the steps taken towards the minimum. It is therefore often necessary to reduce -the global learning rate µ when using a lot of momentum (m close to 1). -If you combine a high learning rate with a lot of momentum, you will rush past the -minimum with huge steps! Read more about it here.

                  -

                  Momentum weight update equation

                  -

                  you can use this option during training:

                  -
                  myNetwork.train(myTrainingSet, {
                  -  error: 0.03,
                  -  iterations: 1000,
                  -  rate: 0.3,
                  -  momentum: 0.9
                  -});
                  -
                  - -

                  Setting the momentum to 0.9 will mean that 90% of the previous weight change -will be included in the current weight change.

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/methods/selection/index.html b/node_modules/neataptic/docs/docs/methods/selection/index.html deleted file mode 100644 index bdd8bcf..0000000 --- a/node_modules/neataptic/docs/docs/methods/selection/index.html +++ /dev/null @@ -1,391 +0,0 @@ - - - Neataptic.js - Selection - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Selection

                  -

                  Edit on Github

                  -
                  -

                  Selection is the -way in which a genetic algorithm decides which neural networks will be parents -for the new generation. There are a couple of selection methods, however only a -few have been integrated until now.

                  -

                  At the moment, there are 3 built-in selection methods:

                  - - - - - - - - - - - - - - - - - -
                  Name
                  selection.POWER
                  selection.FITNESS_PROPORTIONATE
                  selection.TOURNAMENT
                  -

                  A description on how each of these work is given below

                  -

                  Usage

                  -

                  You can specify your selection method while calling the evolve() function on a -network or when constructing a new instance of the NEAT algorithm:

                  -
                  var myNetwork = new architect.Perceptron(1,1,1);
                  -var myTrainingSet = [{ input:[0], output:[1]}, { input:[1], output:[0]}];
                  -
                  -myNetwork.evolve(myTrainingSet, {
                  -  generations: 10,
                  -  selection: methods.selection.POWER // eg.
                  -});
                  -
                  - -

                  Next to selection methods, elitism is also built in the NEAT constructor. -Elitism allows a -genetic algorithm to pass on n neural networks with the highest fitness from -the previous generation to the new generation, without any crossover steps in -between. At the moment, elitism is only possible inside a Neat object. They -can be passed on as follows:

                  -
                  var evolution = new Neat({
                  -  selection: methods.selection.FITNESS_PROPORTIONATE,
                  -  elitism: 5 // amount of neural networks to keep from generation to generation
                  -});
                  -
                  - -

                  methods.selection.POWER

                  -

                  When using this selection method, a random decimal value between 0 and 1 will -be generated. E.g. 0.5, then this value will get an exponential value, the -default power is 4. So 0.5**4 = 0.0625. This will be converted into an index -for the array of the current population, which is sorted from fittest to worst.

                  -

                  Config:

                  -
                    -
                  • methods.selection.POWER.power : default is 4. Increasing this value will -increase the chance fitter genomes are chosen.
                  • -
                  -

                  methods.selection.FITNESS_PROPORTIONATE

                  -

                  This selection method will select genomes with a probability proportionate to their fitness:

                  -

                  Formula

                  -

                  Read more about roulette selection here.

                  -

                  methods.selection.TOURNAMENT

                  -

                  This selection method will select a group of genomes from the population randomly, -sort them by score, and choose the fittest individual with probability p, the -second fittest with probability p*(1-p), the third fittest with probability - p*((1-p)^2)and so on. Read more here.

                  -

                  Config:

                  -
                    -
                  • methods.selection.TOURNAMENT.size : default is 5. Must always be lower than -the population size. A higher value will result in a population that has more -equal, but fitter, parents.
                  • -
                  • methods.selection.TOURNAMENT.probability : default is 0.5. See the -explanation above on how it is implemented.
                  • -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/neat/index.html b/node_modules/neataptic/docs/docs/neat/index.html deleted file mode 100644 index 9e43639..0000000 --- a/node_modules/neataptic/docs/docs/neat/index.html +++ /dev/null @@ -1,505 +0,0 @@ - - - Neataptic.js - NEAT - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  NEAT

                  -

                  Edit on Github

                  -
                  -

                  The built-in NEAT class allows you create evolutionary algorithms with just a few lines of code. If you want to evolve neural networks to conform a given dataset, check out this page. The following code is from the Agario-AI built with Neataptic.

                  -
                  /** Construct the genetic algorithm */
                  -function initNeat(){
                  -  neat = new Neat(
                  -    1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2,
                  -    2,
                  -    null,
                  -    {
                  -      mutation: methods.mutation.ALL
                  -      popsize: PLAYER_AMOUNT,
                  -      mutationRate: MUTATION_RATE,
                  -      elitism: Math.round(ELITISM_PERCENT * PLAYER_AMOUNT),
                  -      network: new architect.Random(
                  -        1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2,
                  -        START_HIDDEN_SIZE,
                  -        2
                  -      )
                  -    }
                  -  );
                  -
                  -  if(USE_TRAINED_POP) neat.population = population;
                  -}
                  -
                  -/** Start the evaluation of the current generation */
                  -function startEvaluation(){
                  -  players = [];
                  -  highestScore = 0;
                  -
                  -  for(var genome in neat.population){
                  -    genome = neat.population[genome];
                  -    new Player(genome);
                  -  }
                  -}
                  -
                  -/** End the evaluation of the current generation */
                  -function endEvaluation(){
                  -  console.log('Generation:', neat.generation, '- average score:', neat.getAverage());
                  -
                  -  neat.sort();
                  -  var newPopulation = [];
                  -
                  -  // Elitism
                  -  for(var i = 0; i < neat.elitism; i++){
                  -    newPopulation.push(neat.population[i]);
                  -  }
                  -
                  -  // Breed the next individuals
                  -  for(var i = 0; i < neat.popsize - neat.elitism; i++){
                  -    newPopulation.push(neat.getOffspring());
                  -  }
                  -
                  -  // Replace the old population with the new population
                  -  neat.population = newPopulation;
                  -  neat.mutate();
                  -
                  -  neat.generation++;
                  -  startEvaluation();
                  -}
                  -
                  - -

                  You might also want to check out the target-seeking project built with Neataptic.

                  -

                  Options

                  -

                  The constructor comes with various options. The constructor works as follows:

                  -
                  new Neat(input, output, fitnessFunction, options); // options should be an object
                  -
                  - -

                  Every generation, each genome will be tested on the fitnessFunction. The -fitness function should return a score (a number). Through evolution, the -genomes will try to maximize the output of the fitness function.

                  -

                  Negative scores are allowed.

                  -

                  You can provide the following options in an object for the options argument:

                  -

                  - popsize - Sets the population size of each generation. Default is 50. -

                  -

                  - elitism - Sets the elitism of every evolution loop. Default is 0. -

                  -

                  - provenance - Sets the provenance of the genetic algorithm. Provenance means that during every evolution, the given amount of genomes will be inserted which all have the original - network template (which is Network(input,output) when no network option is given). Default is 0. -

                  -

                  - mutation -Sets the allowed mutation methods used in the evolutionary process. Must be an array (e.g. [methods.mutation.ADD_NODE, methods.mutation.SUB_NODE]). Default mutation methods are all non-recurrent mutation methods. A random mutation method will be chosen from the array when mutation occrus. -

                  -

                  - selection -Sets the allowed selection method used in the evolutionary process. Must be a single method (e.g. Selection.FITNESS_PROPORTIONATE). Default is FITNESS_PROPORTIONATE. -

                  -

                  - crossover -Sets the allowed crossover methods used in the evolutionary process. Must be an array. disabled as of now -

                  -

                  - fitnessPopulation - If set to true, you will have to specify a fitness function that - takes an array of genomes as input and sets their .score property. -

                  -

                  - mutationRate -Sets the mutation rate. If set to 0.3, 30% of the new population will be mutated. Default is 0.3. -

                  -

                  - mutationAmount -If mutation occurs (randomNumber < mutationRate), sets the amount of times a mutation method will be applied to the network. Default is 1. -

                  -

                  - network -If you want to start the algorithm from a specific network, specify your network here. -

                  -

                  - equal -If set to true, all networks will be viewed equal during crossover. This stimulates more diverse network architectures. Default is false. -

                  -

                  - clear -Clears the context of the network before activating the fitness function. Should be applied to get consistent outputs from recurrent networks. Default is false. -

                  -

                  Properties

                  -

                  There are only a few properties

                  -

                  - input - The amount of input neurons each genome has -

                  -

                  - output - The amount of output neurons each genome has -

                  -

                  - fitness - The fitness function that is used to evaluate genomes -

                  -

                  - generation - Generation counter -

                  -

                  - population - An array containing all the genomes of the current generation -

                  -

                  Functions

                  -

                  There are a few built-in functions. For the client, only getFittest() and evolve() is important. In the future, there will be a combination of backpropagation and evolution. Stay tuned

                  -

                  - createPool() - Initialises the first set of genomes. Should not be called manually. -

                  -

                  - async evolve() - Loops the generation through a evaluation, selection, crossover and mutation process. -

                  -

                  - async evaluate() - Evaluates the entire population by passing on the genome to the fitness function and taking the score. -

                  -

                  - sort() - Sorts the entire population by score. Should be called after evaluate() -

                  -

                  - getFittest() - Returns the fittest genome (highest score) of the current generation -

                  -

                  - mutate() - Mutates genomes in the population, each genome has mutationRate chance of being mutated. -

                  -

                  - getOffspring() - This function selects two genomes from the population with getParent(), and returns the offspring from those parents. -

                  -

                  - getAverage() - Returns the average fitness of the current population -

                  -

                  - getParent() - Returns a parent selected using one of the selection methods provided. Should be called after evaluation. Should not be called manually. -

                  -

                  - export() - Exports the current population of the set up algorithm to a list containing json objects of the networks. Can be used later with import(json) to reload the population -

                  -

                  - import(json) - Imports population from a json. Must be an array of networks that have converted to json (with myNetwork.toJSON()) -

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/tutorials/evolution/index.html b/node_modules/neataptic/docs/docs/tutorials/evolution/index.html deleted file mode 100644 index e56eb0b..0000000 --- a/node_modules/neataptic/docs/docs/tutorials/evolution/index.html +++ /dev/null @@ -1,402 +0,0 @@ - - - Neataptic.js - Evolution - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Evolution

                  -

                  Edit on Github

                  -
                  -

                  Neuro-evolution is something that is fairly underused in the machine learning -community. It is quite interesting to see new architectures develop for -complicated problems. In this guide I will tell you how to set up a simple -supervised neuro-evolution process. If you want to do an unsupervised -neuro-evolution process, head over to the NEAT page.

                  -

                  The training set

                  -

                  You always have to supply a training set for supervised learning. First of all, -you should normalize your data. That means you have to convert all your input and -output data to values within a range of 0 to 1. If you are unsure how to do -this, visit the Normalization tutorial. Each training sample -in your training set should be an object that looks as follows:

                  -
                  { input: [], output: [] }
                  -
                  - -

                  So an example of a training set would be (XOR):

                  -
                  var myTrainingSet = [
                  -  { input: [0,0], output: [0] },
                  -  { input: [0,1], output: [1] },
                  -  { input: [1,0], output: [1] },
                  -  { input: [1,1], output: [0] }
                  -];
                  -
                  - -

                  The network architecture

                  -

                  You can start off with any architecture. You can even use the evolution process -to optimize already trained networks. However, I advise you to start with an empty -network, as originally described in the NEAT - paper. The constructor of an empty network is as follows:

                  -
                  var myNetwork = new Network(inputSize, outputSize);
                  -
                  - -

                  So for the training set I made above, the network can be constructed as follows:

                  -
                  var myNetwork = new Network(2, 1); // 2 inputs, 1 output
                  -
                  - -

                  Now we have our network. We don't have to tinker around anymore; the evolution -process will do that for us.

                  -

                  Evolving the network

                  -

                  Be warned: there are a lot of options involved in the evolution of a process. -It's a matter of trial and error before you reach options that work really well. -Please note that most options are optional, as default values have been configured.

                  -

                  Please note that the evolve function is an async function, so you need to wrap -it in an async function to call await.

                  -

                  The evolve function is as follows:

                  -
                  yourNetwork.evolve(yourData, yourOptions);
                  -
                  - -

                  Check out the evolution options here and here. I'm going to use the following options to evolve the network:

                  -
                    -
                  • mutation: methods.mutation.FFW - I want to solve a feed forward problem, so I supply all feed forward mutation methods. More info here.
                  • -
                  • equal: true - During the crossover process, parent networks will be equal. This allows the spawning of new network architectures more easily.
                  • -
                  • popsize: 100 - The default population size is 50, but 100 worked better for me.
                  • -
                  • elitism: 10 - I want to keep the fittest 10% of the population to the next generation without breeding them.
                  • -
                  • log: 10 - I want to log the status every 10 iterations.
                  • -
                  • error: 0.03 - I want the evolution process when the error is below 0.03;
                  • -
                  • iterations: 1000 - I want the evolution process to stop after 1000 iterations if the target error hasn't been reached yet.
                  • -
                  • mutationRate: 0.5 - I want to increase the mutation rate to surpass possible local optima.
                  • -
                  -

                  So let's put it all together:

                  -
                  await myNetwork.evolve(myTrainingSet, {
                  -  mutation: methods.mutation.FFW,
                  -  equal: true,
                  -  popsize: 100,
                  -  elitism: 10,
                  -  log: 10,
                  -  error: 0.03,
                  -  iterations: 1000,
                  -  mutationRate: 0.5
                  -});
                  -
                  -// results: {error: 0.0009000000000000001, generations: 255, time: 1078}
                  -// please note that there is a hard local optima that has to be beaten
                  -
                  - -

                  Now let us check if it actually works:

                  -
                  myNetwork.activate([0,0]); // [0]
                  -myNetwork.activate([0,1]); // [1]
                  -myNetwork.activate([1,0]); // [1]
                  -myNetwork.activate([1,1]); // [0]
                  -
                  - -

                  Notice how precise the results are. That is because the evolution process makes -full use of the diverse activation functions. It actually uses the Activation.STEP -function to get a binary 0 and 1 output.

                  -

                  Help

                  -

                  If you need more help, feel free to create an issue here!

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/tutorials/normalization/index.html b/node_modules/neataptic/docs/docs/tutorials/normalization/index.html deleted file mode 100644 index dc6742d..0000000 --- a/node_modules/neataptic/docs/docs/tutorials/normalization/index.html +++ /dev/null @@ -1,401 +0,0 @@ - - - Neataptic.js - Normalization - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Normalization

                  -

                  Edit on Github

                  -
                  -

                  Although Neataptic networks accepts non-normalized values as input, normalizing your input makes your network converge faster. I see a lot of questions where people ask how to normalize their data correctly, so I decided to make a guide.

                  -

                  Example data

                  -

                  You have gathered this information, now you want to use it to train/activate a neural network:

                  -
                  { stock: 933, sold: 352, price: 0.95,   category: 'drinks',      id: 40 }
                  -{ stock: 154, sold: 103, price: 5.20,   category: 'foods',       id: 67 }
                  -{ stock: 23,  sold: 5,   price: 121.30, category: 'electronics', id: 150 }
                  -
                  - -

                  So some information on the above data: - stock: the amount of this item in stock - sold: the amount of this item sold ( in the last month ) - price: the price of this item - category: the type of product -* id: the id of the product

                  -

                  Normalize

                  -

                  So we want to represent each of these inputs as a number between 0 and 1, however, we can not change the relativity between the values. So we need to treat each different input the same (stock gets treated the same for every item for example).

                  -

                  We have two types of values in our input data: numerical values and categorical values. These should always be treated differently.

                  -

                  Numerical values

                  -

                  Numerical values are values where the distance between two values matters. For example, price: 0.95 is twice as small as price: 1.90. But not all integers/decimals are numerical values. Id's are often represented with numbers, but there is no relation between id: 4 and id: 8 . So these should be treated as categorical values.

                  -

                  Normalizing numerical values is quite easy, we just need to determine a maximum value we divide a certain input with. For example, we have the following data:

                  -
                  stock: 933
                  -stock: 154
                  -stock: 23
                  -
                  - -

                  We need to choose a value which is >= 933 with which we divide all the stock values. We could choose 933, but what if we get new data, where the stock value is higher than 933? Then we have to renormalize all the data and retrain the network.

                  -

                  So we need to choose a value that is >=933, but also >= future values and it shouldn't be a too big number. We could make the assumption that the stock will never get larger than 2000, so we choose 2000 as our maximum value. We now normalize our data with this maximum value:

                  -
                  // Normalize the data with a maximum value (=2000)
                  -stock: 933 -> 933/2000 -> 0.4665
                  -stock: 154 -> 154/2000 -> 0.077
                  -stock: 23  ->  23/2000 -> 0.0115
                  -
                  - -

                  Categorical data

                  -

                  Categorical data shows no relation between different categories. So each category should be treated as a seperate input, this is called one-hot encoding. Basically, you create a seperate input for each category. You set all the inputs to 0, except for the input which matches the sample category. This is one-hot encoding for our above training data:

                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  SampleDrinksFoodsElectronics
                  1100
                  2010
                  3001
                  - -

                  But this also allows the addition of new categories over time: you just a need input. It has no effect on the performances of the network on the past training data as when the new category is set to 0, it has no effect (weight * 0 = 0).

                  -

                  Normalized data

                  -

                  So applying what I have explained above creates our normalized data, note that the relativity between inputs has not been changed. Also note that some values may be rounded in the table below.

                  -
                  { stock: 0.4665, sold: 0.352, price: 0.00317, drinks: 1, foods: 0, electronics: 0, id40: 1, id67: 0, id150: 0 }
                  -{ stock: 0.077,  sold: 0.103, price: 0.01733, drinks: 0, foods: 1, electronics: 0, id40: 0, id67: 1, id150: 0 }
                  -{ stock: 0.0115, sold: 0.005, price: 0.40433, drinks: 0, foods: 0, electronics: 1, id40: 0, id67: 0, id150: 1 }
                  -
                  - -

                  Max values:

                  -
                    -
                  • stock: 2000
                  • -
                  • sold: 1000
                  • -
                  • price : 300
                  • -
                  -

                  Please note, that these inputs should be provided in arrays for neural networks in Neataptic:

                  -
                  [ 0.4665, 0.352, 0.00317, 1, 0, 0, 1, 0, 0 ]
                  -[ 0.77,   0.103, 0.01733, 0, 1, 0, 0, 1, 0 ]
                  -[ 0.0115, 0.005, 0.40433, 0, 0, 1, 0, 0, 1 ]
                  -
                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/tutorials/training/index.html b/node_modules/neataptic/docs/docs/tutorials/training/index.html deleted file mode 100644 index 0a7a41b..0000000 --- a/node_modules/neataptic/docs/docs/tutorials/training/index.html +++ /dev/null @@ -1,377 +0,0 @@ - - - Neataptic.js - Training - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Training

                  -

                  Edit on Github

                  -
                  -

                  Training your network is not that hard to do - it's the preparation that is harder.

                  -

                  The training set

                  -

                  First of all, you should normalize your data. That means you have to convert all your input and output data to values within a range of 0 to 1. If you are unsure how to do this, visit the Normalization page. Each training sample in your training set should be an object that looks as follows:

                  -
                  { input: [], output: [] }
                  -
                  - -

                  So an example of a training set would be (XOR):

                  -
                  var myTrainingSet = [
                  -  { input: [0,0], output: [0] },
                  -  { input: [0,1], output: [1] },
                  -  { input: [1,0], output: [1] },
                  -  { input: [1,1], output: [0] }
                  -];
                  -
                  - -

                  The network architecture

                  -

                  There is no fixed rule of thumb for choosing your network architecture. Adding more layers makes your neural network recognize more abstract relationships, although it requires more computation. Any function can be mapped with just one (big) hidden layer, but I do not advise this. I advise to use any of the following architectures if you're a starter:

                  -
                    -
                  • Perceptron - a fully connected feed forward network
                  • -
                  • LSTM - a recurrent network that can recognize patterns over very long time lags between inputs.
                  • -
                  • NARX - a recurrent network that remembers previous inputs and outputs
                  • -
                  -

                  But for most problems, a perceptron is sufficient. Now you only have to determine the size and amount of the network layers. I advise you to take a look at this StackExchange question for more help on deciding the hidden size.

                  -

                  For the training set I provided above (XOR), there are only 2 inputs and one output. I use the rule of thumb: input size + output size = hidden size. So the creation of my network would like this:

                  -
                  myNetwork = architect.Perceptron(2, 3, 1);
                  -
                  - -

                  Training the network

                  -

                  Finally: we're going to train the network. The function for training your network is very straight-forward:

                  -
                  yourNetwork.train(yourData, yourOptions);
                  -
                  - -

                  There are a lot of options. I won't go over all of them here, but you can check out the Network wiki for all the options.

                  -

                  I'm going to use the following options:

                  -
                    -
                  • log: 10 - I want to log the status every 10 iterations
                  • -
                  • error: 0.03 - I want the training to stop if the error is below 0.03
                  • -
                  • iterations: 1000 - I want the training to stop if the error of 0.03 hasn't been reached after 1000 iterations
                  • -
                  • rate: 0.3 - I want a learning rate of 0.3
                  • -
                  -

                  So let's put it all together:

                  -
                  myNetwork.train(myTrainingSet, {
                  -  log: 10,
                  -  error: 0.03,
                  -  iterations: 1000,
                  -  rate: 0.3
                  -});
                  -
                  -// result: {error: 0.02955628620843985, iterations: 566, time: 31}
                  -
                  - -

                  Now let us check if it actually works:

                  -
                  myNetwork.activate([0,0]); // [0.1257225731473885]
                  -myNetwork.activate([0,1]); // [0.9371910625522613]
                  -myNetwork.activate([1,0]); // [0.7770757408042104]
                  -myNetwork.activate([1,1]); // [0.1639697315652196]
                  -
                  - -

                  And it works! If you want it to be more precise, lower the target error.

                  -

                  Help

                  -

                  If you need more help, feel free to create an issue here!

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/tutorials/tutorials/index.html b/node_modules/neataptic/docs/docs/tutorials/tutorials/index.html deleted file mode 100644 index bcff593..0000000 --- a/node_modules/neataptic/docs/docs/tutorials/tutorials/index.html +++ /dev/null @@ -1,321 +0,0 @@ - - - Neataptic.js - Tutorials - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Tutorials

                  -

                  Edit on Github

                  -
                  -

                  In order to get you started on Neataptic, a few tutorials have been written that -give a basic overview on how to create, train and evolve your networks. It is -recommended to read all of them before you start digging in your own project.

                  - -

                  If you have any questions, feel free to create an issue here. -If you feel like anything is missing, feel free to create a pull request!

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/docs/tutorials/visualization/index.html b/node_modules/neataptic/docs/docs/tutorials/visualization/index.html deleted file mode 100644 index b7c6d21..0000000 --- a/node_modules/neataptic/docs/docs/tutorials/visualization/index.html +++ /dev/null @@ -1,383 +0,0 @@ - - - Neataptic.js - Visualization - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  - -
                  - - -
                  - - -
                  -

                  Visualization

                  -

                  Edit on Github

                  -
                  -

                  This is a step-by-step tutorial aimed to teach you how to create and visualise neural networks using Neataptic.

                  -

                  Step 1 -Create a javascript file. Name it anything you want. But make sure to start it off with the following:

                  -
                  var Node = neataptic.Node;
                  -var Neat = neataptic.Neat;
                  -var Network = neataptic.Network;
                  -var Methods = neataptic.Methods;
                  -var Architect = neataptic.Architect;
                  -
                  - -

                  This makes the whole developing a whole lot easier

                  -

                  Step 2 -Create a html file. Copy and paste this template if you want:

                  -
                  <html>
                  -  <head>
                  -    <script src="http://d3js.org/d3.v3.min.js"></script>
                  -    <script src="http://marvl.infotech.monash.edu/webcola/cola.v3.min.js"></script>
                  -
                  -    <script src="https://rawgit.com/wagenaartje/neataptic/master/dist/neataptic.js"></script>
                  -    <script src="https://rawgit.com/wagenaartje/neataptic/master/graph/graph.js"></script>
                  -    <link rel="stylesheet" type="text/css" href="https://rawgit.com/wagenaartje/neataptic/master/graph/graph.css">
                  -  </head>
                  -  <body>
                  -    <div class="container">
                  -      <div class="row">
                  -        <svg class="draw" width="1000px" height="1000px"/>
                  -      </div>
                  -    </div>
                  -    <script src="yourscript.js"></script>
                  -  </body>
                  -</html>
                  -
                  - -

                  Step 3 Create a network. You can do that in any of the following ways:

                  -
                  var network = architect.Random(2, 20, 2, 2);
                  -
                  - -
                  var network = architect.Perceptron(2, 10, 10, 2);
                  -
                  - -

                  Or if you want to be more advanced, construct your own:

                  -
                  var A = new Node();
                  -var B = new Node();
                  -var C = new Node();
                  -var D = new Node();
                  -var E = new Node();
                  -var F = new Node();
                  -
                  -var nodes = [A, B, C, D, E, F];
                  -
                  -for(var i = 0; i < nodes.length-1; i++){
                  -  node = nodes[i];
                  -  for(var j = 0; j < 2; j++){
                  -    var connectTo = nodes[Math.floor(Math.random() * (nodes.length - i) + i)];
                  -    node.connect(connectTo);
                  -  }
                  -}
                  -
                  -var network = architect.Construct(nodes);
                  -
                  - -

                  Step 4 Retrieve data and draw a graph

                  -
                  drawGraph(network.graph(1000, 1000), '.draw');
                  -
                  - -

                  See a working example here! -See more info on graphs here!

                  -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/fonts/fontawesome-webfont.eot b/node_modules/neataptic/docs/fonts/fontawesome-webfont.eot deleted file mode 100644 index 9b6afae..0000000 Binary files a/node_modules/neataptic/docs/fonts/fontawesome-webfont.eot and /dev/null differ diff --git a/node_modules/neataptic/docs/fonts/fontawesome-webfont.svg b/node_modules/neataptic/docs/fonts/fontawesome-webfont.svg deleted file mode 100644 index d05688e..0000000 --- a/node_modules/neataptic/docs/fonts/fontawesome-webfont.svg +++ /dev/null @@ -1,655 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/fonts/fontawesome-webfont.ttf b/node_modules/neataptic/docs/fonts/fontawesome-webfont.ttf deleted file mode 100644 index 26dea79..0000000 Binary files a/node_modules/neataptic/docs/fonts/fontawesome-webfont.ttf and /dev/null differ diff --git a/node_modules/neataptic/docs/fonts/fontawesome-webfont.woff b/node_modules/neataptic/docs/fonts/fontawesome-webfont.woff deleted file mode 100644 index dc35ce3..0000000 Binary files a/node_modules/neataptic/docs/fonts/fontawesome-webfont.woff and /dev/null differ diff --git a/node_modules/neataptic/docs/fonts/fontawesome-webfont.woff2 b/node_modules/neataptic/docs/fonts/fontawesome-webfont.woff2 deleted file mode 100644 index 500e517..0000000 Binary files a/node_modules/neataptic/docs/fonts/fontawesome-webfont.woff2 and /dev/null differ diff --git a/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.eot b/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.eot deleted file mode 100644 index b93a495..0000000 Binary files a/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.eot and /dev/null differ diff --git a/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.svg b/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.svg deleted file mode 100644 index 94fb549..0000000 --- a/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.svg +++ /dev/null @@ -1,288 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.ttf b/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.ttf deleted file mode 100644 index 1413fc6..0000000 Binary files a/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.ttf and /dev/null differ diff --git a/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.woff b/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.woff deleted file mode 100644 index 9e61285..0000000 Binary files a/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.woff and /dev/null differ diff --git a/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.woff2 b/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.woff2 deleted file mode 100644 index 64539b5..0000000 Binary files a/node_modules/neataptic/docs/fonts/glyphicons-halflings-regular.woff2 and /dev/null differ diff --git a/node_modules/neataptic/docs/img/favicon.ico b/node_modules/neataptic/docs/img/favicon.ico deleted file mode 100644 index e85006a..0000000 Binary files a/node_modules/neataptic/docs/img/favicon.ico and /dev/null differ diff --git a/node_modules/neataptic/docs/img/grid.png b/node_modules/neataptic/docs/img/grid.png deleted file mode 100644 index 878c3ed..0000000 Binary files a/node_modules/neataptic/docs/img/grid.png and /dev/null differ diff --git a/node_modules/neataptic/docs/index.html b/node_modules/neataptic/docs/index.html deleted file mode 100644 index 9e53893..0000000 --- a/node_modules/neataptic/docs/index.html +++ /dev/null @@ -1,148 +0,0 @@ - - - Neataptic.js - Home - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                  -
                  -
                  - -
                  -
                  -

                  Neuro-evolution on steroids, right in the browser

                  -

                  Using the Instinct algorithm

                  -
                  -
                  - - - -
                  -
                  -
                  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/node_modules/neataptic/docs/js/articles/agar.ioai/field.js b/node_modules/neataptic/docs/js/articles/agar.ioai/field.js deleted file mode 100644 index 38ab61c..0000000 --- a/node_modules/neataptic/docs/js/articles/agar.ioai/field.js +++ /dev/null @@ -1,92 +0,0 @@ -/* Global vars */ -var players = []; -var foods = []; -var iteration = 0; -var highestScore = 0; - -/** Setup the canvas */ -function setup(){ - var canvas = createCanvas(WIDTH, HEIGHT); - canvas.parent('field'); - initNeat(); - - // Create some food - for(var i = 0; i < FOOD_AMOUNT; i++){ - new Food(); - } - - startEvaluation(); -} - -function draw(){ - clear(); - squareGrid(); - - // Check if evaluation is done - if(iteration == ITERATIONS){ - endEvaluation(); - iteration = 0; - } - - // Update and visualise players - for(var i = players.length - 1; i >= 0; i--){ - var player = players[i]; - - // Some players are eaten during the iteration - player.update(); - player.show(); - } - - // Update and visualise food - for(var i = foods.length - 1; i >= 0; i--){ - foods[i].show(); - } - - iteration++; -} - -/** Draw a square grid with grey lines */ -function squareGrid(){ - stroke(204, 204, 204, 160); - fill(255); - for(var x = 0; x < WIDTH/40; x++){ - line(x * 40, 0, x * 40, HEIGHT); - } - for(var y = 0; y < HEIGHT/40; y++){ - line(0, y * 40, WIDTH, y * 40); - } - noStroke(); -} - -/** Calculate distance between two points */ -function distance(x1, y1, x2, y2){ - var dx = x1 - x2; - var dy = y1 - y2; - - return Math.sqrt(dx * dx + dy * dy); -} - -/** Get a relative color between red and green */ -var activationColor = function(value, max){ - var power = 1 - Math.min(value/max, 1); - var color = [255, 255, 0] - - if(power < 0.5){ - color[0] = 2 * power * 255; - } else { - color[1] = (1.0 - 2 * (power - 0.5)) * 255; - } - - return color; -} - -/** Get the angle from one point to another */ -function angleToPoint(x1, y1, x2, y2){ - d = distance(x1, y1, x2, y2); - dx = (x2-x1) / d; - dy = (y2-y1) / d; - - a = Math.acos(dx); - a = dy < 0 ? 2 * Math.PI - a : a; - return a; -} diff --git a/node_modules/neataptic/docs/js/articles/agar.ioai/food.js b/node_modules/neataptic/docs/js/articles/agar.ioai/food.js deleted file mode 100644 index f43cb82..0000000 --- a/node_modules/neataptic/docs/js/articles/agar.ioai/food.js +++ /dev/null @@ -1,31 +0,0 @@ -function Food(){ - this.x = Math.floor(Math.random() * WIDTH); - this.y = Math.floor(Math.random() * HEIGHT); - this.area = FOOD_AREA; - - this.color = [ - Math.round(Math.random() * 255), - Math.round(Math.random() * 255), - Math.round(Math.random() * 255) - ]; - - foods.push(this); -} - -Food.prototype = { - /** Display the player on the field */ - show: function(){ - var radius = Math.sqrt(this.area / PI); - - fill(this.color[0], this.color[1], this.color[2]); - noStroke(); - ellipse(this.x, this.y, radius); - }, - - /** Restart from new position */ - restart: function(){ - this.x = Math.floor(Math.random() * WIDTH); - this.y = Math.floor(Math.random() * HEIGHT); - }, - -}; diff --git a/node_modules/neataptic/docs/js/articles/agar.ioai/import.js b/node_modules/neataptic/docs/js/articles/agar.ioai/import.js deleted file mode 100644 index eb6142c..0000000 --- a/node_modules/neataptic/docs/js/articles/agar.ioai/import.js +++ /dev/null @@ -1,37 +0,0 @@ -var scripts = [ - { type: 'script', url: "https://cdn.rawgit.com/wagenaartje/neataptic/a7610e38/dist/neataptic.js"}, - { type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.10/p5.js"}, - { type: 'script', url: "../../js/articles/agar.ioai/main.js"}, - { type: 'script', url: "../../js/articles/agar.ioai/population.js"}, - { type: 'script', url: "../../js/articles/agar.ioai/player.js"}, - { type: 'script', url: "../../js/articles/agar.ioai/food.js"}, - { type: 'script', url: "../../js/articles/agar.ioai/field.js"} -]; - -/** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ -function require(list) { - function loadScript(link) { - return new Promise(function(fulfill, reject) { - if(link.type == 'script'){ - var script = document.createElement("script"); - script.addEventListener("load", fulfill); - script.src = link.url; - document.head.appendChild(script); - } else if(link.type == 'css'){ - var stylesheet = document.createElement('link'); - stylesheet.rel = 'stylesheet'; - stylesheet.type = 'text/css'; - stylesheet.href = link.url; - stylesheet.media = "screen,print"; - document.head.appendChild(stylesheet); - } - }); - } - loadScript(list.shift()).then(function() { - if (list.length > 0) { - require(list); - } - }) -} - -require(scripts); diff --git a/node_modules/neataptic/docs/js/articles/agar.ioai/main.js b/node_modules/neataptic/docs/js/articles/agar.ioai/main.js deleted file mode 100644 index aec129f..0000000 --- a/node_modules/neataptic/docs/js/articles/agar.ioai/main.js +++ /dev/null @@ -1,113 +0,0 @@ -/** Rename vars */ -var Neat = neataptic.Neat; -var Methods = neataptic.Methods; -var Config = neataptic.Config; -var Architect = neataptic.Architect; - -/** Turn off warnings */ -Config.warnings = false; - -/** Settings */ -var WIDTH = $('#field').width(); -var HEIGHT = 500; - -var MAX_AREA = 10000; -var MIN_AREA = 400; - -var RELATIVE_SIZE = 1.1; -var DECREASE_SIZE = 0.998; - -var DETECTION_RADIUS = 150; -var FOOD_DETECTION = 3; -var PLAYER_DETECTION = 3; - -var MIN_SPEED = 0.6; -var SPEED = 2; - -var FOOD_AREA = 80; -var FOOD_AMOUNT = Math.round(WIDTH * HEIGHT * 4e-4); - -// GA settings -var PLAYER_AMOUNT = Math.round(WIDTH * HEIGHT * 8e-5); -var ITERATIONS = 10e10; -var START_HIDDEN_SIZE = 0; - -// Trained population -var USE_TRAINED_POP = true; - -// Global vars -var neat; - -/** Construct the genetic algorithm */ -function initNeat(){ - neat = new Neat( - 1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2, - 2, - null, - { - mutation: [ - Methods.Mutation.ADD_NODE, - Methods.Mutation.SUB_NODE, - Methods.Mutation.ADD_CONN, - Methods.Mutation.SUB_CONN, - Methods.Mutation.MOD_WEIGHT, - Methods.Mutation.MOD_BIAS, - Methods.Mutation.MOD_ACTIVATION, - Methods.Mutation.ADD_GATE, - Methods.Mutation.SUB_GATE, - Methods.Mutation.ADD_SELF_CONN, - Methods.Mutation.SUB_SELF_CONN, - Methods.Mutation.ADD_BACK_CONN, - Methods.Mutation.SUB_BACK_CONN - ], - popsize: PLAYER_AMOUNT, - mutationRate: 0.3, - elitism: Math.round(0.1 * PLAYER_AMOUNT), - network: new Architect.Random( - 1 + PLAYER_DETECTION * 3 + FOOD_DETECTION * 2, - START_HIDDEN_SIZE, - 2 - ) - } - ); - - if(USE_TRAINED_POP){ - neat.population = population; - } -} - -/** Start the evaluation of the current generation */ -function startEvaluation(){ - players = []; - highestScore = 0; - - for(var genome in neat.population){ - genome = neat.population[genome]; - new Player(genome); - } -} - -/** End the evaluation of the current generation */ -function endEvaluation(){ - console.log('Generation:', neat.generation, '- average score:', neat.getAverage()); - - neat.sort(); - var newPopulation = []; - - // Elitism - for(var i = 0; i < neat.elitism; i++){ - newPopulation.push(neat.population[i]); - } - - // Breed the next individuals - for(var i = 0; i < neat.popsize - neat.elitism; i++){ - newPopulation.push(neat.getOffspring()); - } - - // Replace the old population with the new population - neat.population = newPopulation; - neat.mutate(); - - neat.generation++; - startEvaluation(); -} diff --git a/node_modules/neataptic/docs/js/articles/agar.ioai/player.js b/node_modules/neataptic/docs/js/articles/agar.ioai/player.js deleted file mode 100644 index 1986096..0000000 --- a/node_modules/neataptic/docs/js/articles/agar.ioai/player.js +++ /dev/null @@ -1,180 +0,0 @@ -function Player(genome){ - this.x = Math.floor(Math.random() * WIDTH); - this.y = Math.floor(Math.random() * HEIGHT); - this.vx = 0; - this.vy = 0; - - this.brain = genome; - this.brain.score = 0; - - this.area = MIN_AREA; - this.visualarea = this.area; - - players.push(this); -} - -Player.prototype = { - /** Update the stats */ - update: function(){ - if(this.area > MAX_AREA) this.area = MAX_AREA; - if(this.area < MIN_AREA) this.area = MIN_AREA; - - var input = this.detect(); - var output = this.brain.activate(input); - - var moveangle = output[0] * 2 * PI; - var movespeed = output[1] > 1 ? 1 : output[1] < 0 ? 0 : output[1]; - - this.vx = movespeed * Math.cos(moveangle) * SPEED; - this.vy = movespeed * Math.sin(moveangle) * SPEED; - - // Large blobs move slower - this.vx *= Math.max(1 - (this.area / MAX_AREA), MIN_SPEED / SPEED); - this.vy *= Math.max(1 - (this.area / MAX_AREA), MIN_SPEED / SPEED); - - this.x += this.vx; - this.y += this.vy; - - // Limit position to width and height - this.x = this.x >= WIDTH ? this.x % WIDTH : this.x <= 0 ? this.x + WIDTH : this.x; - this.y = this.y >= HEIGHT ? this.y % HEIGHT : this.y <= 0 ? this.y + HEIGHT : this.y; - - this.area *= DECREASE_SIZE; - - // Replace highest score to visualise - this.brain.score = this.area; - highestScore = this.brain.score > highestScore ? this.brain.score : highestScore; - }, - - /** Restart from new position */ - restart: function(){ - this.x = Math.floor(Math.random() * WIDTH); - this.y = Math.floor(Math.random() * HEIGHT); - this.vx = 0; - this.vy = 0; - this.area = MIN_AREA; - this.visualarea = this.area; - }, - - /** Display the player on the field */ - show: function(){ - this.visualarea = lerp(this.visualarea, this.area, 0.2); - var radius = Math.sqrt(this.visualarea / PI); - var color = activationColor(this.brain.score, highestScore); - - fill(color); - ellipse(this.x, this.y, radius); - }, - - /** Visualies the detection of the brain */ - showDetection: function(detected){ - noFill(); - for(var object in detected){ - object = detected[object]; - - if(object != undefined){ - stroke(object instanceof Player ? 'red' : 'lightgreen'); - line(this.x, this.y, object.x, object.y); - } - } - - var color = activationColor(this.brain.score, highestScore); - stroke(color); - ellipse(this.x, this.y, DETECTION_RADIUS*2); - noStroke(); - }, - - /* Checks if object can be eaten */ - eat: function(object){ - var dist = distance(this.x, this.y, object.x, object.y); - - var radius1 = Math.sqrt(this.area / PI); - var radius2 = Math.sqrt(object.area / PI); - if(dist < (radius1 + radius2) / 2 && this.area > object.area * RELATIVE_SIZE){ - this.area += object.area; - object.restart(); - return true; - } - return false; - }, - - /** Detect other genomes around */ - detect: function(){ - // Detect nearest objects - var nearestPlayers = []; - var playerDistances = Array.apply(null, Array(PLAYER_DETECTION)).map(Number.prototype.valueOf, Infinity); - - for(var player in players){ - player = players[player]; - if(player == this || this.eat(player)) continue; - - var dist = distance(this.x, this.y, player.x, player.y); - if(dist < DETECTION_RADIUS){ - // Check if closer than any other object - var maxNearestDistance = Math.max.apply(null, playerDistances); - var index = playerDistances.indexOf(maxNearestDistance); - - if(dist < maxNearestDistance){ - playerDistances[index] = dist; - nearestPlayers[index] = player; - } - } - } - - // Detect nearest foods - var nearestFoods = []; - var foodDistances = Array.apply(null, Array(FOOD_DETECTION)).map(Number.prototype.valueOf, Infinity); - - for(var food in foods){ - food = foods[food]; - if(this.eat(food)) continue; - - var dist = distance(this.x, this.y, food.x, food.y); - if(dist < DETECTION_RADIUS){ - // Check if closer than any other object - var maxNearestDistance = Math.max.apply(null, foodDistances); - var index = foodDistances.indexOf(maxNearestDistance); - - if(dist < maxNearestDistance){ - foodDistances[index] = dist; - nearestFoods[index] = food; - } - } - } - - // Create and normalize input - var output = [this.area / MAX_AREA]; - - for(var i = 0; i < PLAYER_DETECTION; i++){ - var player = nearestPlayers[i]; - var dist = playerDistances[i]; - - if(player == undefined){ - output = output.concat([0, 0, 0]); - } else { - output.push(angleToPoint(this.x, this.y, player.x, player.y) / (2 * PI)); - output.push(dist / DETECTION_RADIUS); - output.push(player.area / MAX_AREA); - } - } - - for(var i = 0; i < FOOD_DETECTION; i++){ - var food = nearestFoods[i]; - var dist = foodDistances[i]; - - if(food == undefined){ - output = output.concat([0, 0]); - } else { - output.push(angleToPoint(this.x, this.y, food.x, food.y) / (2 * PI)); - output.push(dist / DETECTION_RADIUS); - } - } - - if(distance(mouseX, mouseY, this.x, this.y) < Math.sqrt(this.visualarea / PI)){ - var detected = nearestPlayers.concat(nearestFoods); - this.showDetection(detected); - } - - return output; - }, -}; diff --git a/node_modules/neataptic/docs/js/articles/agar.ioai/population.js b/node_modules/neataptic/docs/js/articles/agar.ioai/population.js deleted file mode 100644 index 21b84b2..0000000 --- a/node_modules/neataptic/docs/js/articles/agar.ioai/population.js +++ /dev/null @@ -1,29160 +0,0 @@ -var population = [ - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.7720866327218414, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":11 - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":0.040529167694171475, - "type":"hidden", - "squash":"RELU", - "index":"16" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"17" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"18" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":17, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":18, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":17, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":18, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":18, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":18, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":18, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.028472043972609412, - "from":8, - "to":18, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":18, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":18, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":17, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":18, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":18, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":18, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":18, - "to":17, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":17, - "to":18, - "gater":null - }, - { - "weight":-0.059514645508516664, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.008616698980009468, - "from":16, - "to":18, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":0.031123400422858716, - "from":16, - "to":17, - "gater":0 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"LOGISTIC", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":11 - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":0.048629215983209045, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":1, - "from":"17", - "to":"17", - "gater":null - }, - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.01636191553373663, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":0.048629215983209045, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":6 - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":0.048629215983209045, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":6 - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":-0.07623454218397559, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"TANH", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.062063537579453154, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":6 - }, - { - "weight":0.06400114126666279, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"LOGISTIC", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":11 - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.4666144667781344, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":6 - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.041440394790798245, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":11 - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.01636191553373663, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.03226929236372622, - "from":13, - "to":16, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.035507973704412166, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":6 - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.5411052196882778, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"LOGISTIC", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":0.031123400422858716, - "from":16, - "to":17, - "gater":0 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":11 - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":8 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"LOGISTIC", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - }, - { - "weight":0.09277510317981347, - "from":13, - "to":16, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":11 - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.4666144667781344, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"17" - } - ], - "connections":[ - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":0.048629215983209045, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":17, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":0.06400114126666279, - "from":15, - "to":16, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":-0.22115847009287437, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":5 - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":-0.22115847009287437, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":1, - "from":"17", - "to":"17", - "gater":null - }, - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":-0.05831571100501525, - "from":0, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.25440656353450486, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.5411052196882778, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":6 - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"LOGISTIC", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"LOGISTIC", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.04823154862817334, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.5411052196882778, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":-0.6134351458932366, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":0.006330555912326119, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":6 - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":0.031123400422858716, - "from":16, - "to":17, - "gater":0 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.041440394790798245, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":0 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.6552225583963397, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":1.2515240304540414, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":0.048629215983209045, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"17" - } - ], - "connections":[ - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.05724869156011511, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.03226929236372622, - "from":13, - "to":16, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-0.04563341160455297, - "type":"hidden", - "squash":"IDENTITY", - "index":"16" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"17" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"18" - } - ], - "connections":[ - { - "weight":0.045008688836155025, - "from":1, - "to":18, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":18, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":18, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":18, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":18, - "gater":4 - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":18, - "gater":1 - }, - { - "weight":0.03852615092597875, - "from":8, - "to":18, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":18, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":18, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":18, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":18, - "gater":6 - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":18, - "gater":null - }, - { - "weight":-0.03099810573835496, - "from":0, - "to":17, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":17, - "gater":null - }, - { - "weight":0.06400114126666279, - "from":15, - "to":17, - "gater":null - }, - { - "weight":-0.0181113313454333, - "from":16, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":18, - "to":17, - "gater":null - }, - { - "weight":-0.041440394790798245, - "from":17, - "to":18, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"LOGISTIC", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":-0.028472043972609412, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.3533792976609607, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.01636191553373663, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"TANH", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.002893178380447378, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"LOGISTIC", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.4666144667781344, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":6 - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":0.048629215983209045, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":1 - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":6 - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":0.06400114126666279, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":-0.028472043972609412, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"LOGISTIC", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":null - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.01690810962568659, - "from":16, - "to":17, - "gater":15 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":-1.4400212676737092, - "type":"output", - "squash":"GAUSSIAN", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":0 - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.4068723913490687, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":-0.0058927706667381285, - "from":9, - "to":17, - "gater":14 - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":6 - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.041440394790798245, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.398685952675371, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":null - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":11 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":6 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.034970101142611745, - "from":16, - "to":17, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":16, - "gater":6 - } - ], - "input":16, - "output":2 - }, - { - "nodes":[ - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"0" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"1" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"2" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"3" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"4" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"5" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"6" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"7" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"8" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"9" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"10" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"11" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"12" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"13" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"14" - }, - { - "bias":0, - "type":"input", - "squash":"LOGISTIC", - "index":"15" - }, - { - "bias":-1.4717517509742422, - "type":"output", - "squash":"GAUSSIAN", - "index":"16" - }, - { - "bias":0.3087436497338314, - "type":"output", - "squash":"HLIM", - "index":"17" - } - ], - "connections":[ - { - "weight":-0.03099810573835496, - "from":0, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":16, - "gater":null - }, - { - "weight":-0.042673416967570876, - "from":2, - "to":16, - "gater":null - }, - { - "weight":0.045008688836155025, - "from":1, - "to":17, - "gater":null - }, - { - "weight":0.08728755494684406, - "from":3, - "to":16, - "gater":null - }, - { - "weight":1.4402201419923903, - "from":2, - "to":17, - "gater":15 - }, - { - "weight":0.05091566974540393, - "from":4, - "to":16, - "gater":1 - }, - { - "weight":0.05184046817163149, - "from":5, - "to":16, - "gater":null - }, - { - "weight":0.05091566974540393, - "from":4, - "to":17, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":16, - "gater":null - }, - { - "weight":0.04729527424867816, - "from":5, - "to":17, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":16, - "gater":null - }, - { - "weight":-0.25185140261031774, - "from":6, - "to":17, - "gater":4 - }, - { - "weight":0.056206289109127255, - "from":8, - "to":16, - "gater":null - }, - { - "weight":-0.003276566860253502, - "from":7, - "to":17, - "gater":1 - }, - { - "weight":0.030357374200478654, - "from":9, - "to":16, - "gater":null - }, - { - "weight":0.03852615092597875, - "from":8, - "to":17, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":16, - "gater":null - }, - { - "weight":0.030357374200478654, - "from":9, - "to":17, - "gater":null - }, - { - "weight":-0.035414690266642526, - "from":11, - "to":16, - "gater":null - }, - { - "weight":0.0492182017687659, - "from":10, - "to":17, - "gater":null - }, - { - "weight":0.019086008191027834, - "from":12, - "to":16, - "gater":null - }, - { - "weight":-0.5024907442751645, - "from":11, - "to":17, - "gater":null - }, - { - "weight":1.0069164221380793, - "from":14, - "to":16, - "gater":null - }, - { - "weight":-0.06147474963938953, - "from":13, - "to":17, - "gater":6 - }, - { - "weight":0.06400114126666279, - "from":15, - "to":16, - "gater":null - }, - { - "weight":-0.04206229870333389, - "from":15, - "to":17, - "gater":null - }, - { - "weight":0.036226918338303216, - "from":17, - "to":16, - "gater":null - }, - { - "weight":-0.032562723951449754, - "from":16, - "to":17, - "gater":null - } - ], - "input":16, - "output":2 - } -]; - -// Convert the json to an array of networks -var newPop = []; -for(var i = 0; i < PLAYER_AMOUNT; i++){ - var json = population[i % population.length]; - newPop[i] = neataptic.Network.fromJSON(json); -} -population = newPop; diff --git a/node_modules/neataptic/docs/js/articles/classifycolors/custom.css b/node_modules/neataptic/docs/js/articles/classifycolors/custom.css deleted file mode 100644 index 7f81260..0000000 --- a/node_modules/neataptic/docs/js/articles/classifycolors/custom.css +++ /dev/null @@ -1,8 +0,0 @@ -#circle { - width: 20px; - height: 20px; - -webkit-border-radius: 10px; - -moz-border-radius: 10px; - border-radius: 10px; - display: inline-block; -} diff --git a/node_modules/neataptic/docs/js/articles/classifycolors/events.js b/node_modules/neataptic/docs/js/articles/classifycolors/events.js deleted file mode 100644 index 70b6a98..0000000 --- a/node_modules/neataptic/docs/js/articles/classifycolors/events.js +++ /dev/null @@ -1,24 +0,0 @@ -$('.colors').change(function(){ - var color = $(this).attr('value'); - if($(this).is(":checked")) { - COLORS.push(color); - } else { - COLORS.splice(COLORS.indexOf(color), 1); - } - - set = createSet(); - visualiseSet(); -}); -$('.start').click(function(e){ - e.preventDefault(); - if(running == false){ - running = true; - iteration = 0; - createNeat(); - $(this).html(' Stop evolution'); - setTimeout(loop, 1); - } else { - running = false; - $(this).html(' Start evolution'); - } -}); diff --git a/node_modules/neataptic/docs/js/articles/classifycolors/import.js b/node_modules/neataptic/docs/js/articles/classifycolors/import.js deleted file mode 100644 index 6c175f7..0000000 --- a/node_modules/neataptic/docs/js/articles/classifycolors/import.js +++ /dev/null @@ -1,35 +0,0 @@ -var scripts = [ - { type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.2.22/neataptic.js" }, - { type: 'script', url: "../../js/articles/classifycolors/events.js" }, - { type: 'script', url: "../../js/articles/classifycolors/randomColor.js" }, - { type: 'script', url: "../../js/articles/classifycolors/neural.js" }, - { type: 'css', url: "../../js/articles/classifycolors/custom.css"} -]; - -/** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ -function require(list) { - function loadScript(link) { - return new Promise(function(fulfill, reject) { - if(link.type == 'script'){ - var script = document.createElement("script"); - script.addEventListener("load", fulfill); - script.src = link.url; - document.head.appendChild(script); - } else if(link.type == 'css'){ - var stylesheet = document.createElement('link'); - stylesheet.rel = 'stylesheet'; - stylesheet.type = 'text/css'; - stylesheet.href = link.url; - stylesheet.media = "screen,print"; - document.head.appendChild(stylesheet); - } - }); - } - loadScript(list.shift()).then(function() { - if (list.length > 0) { - require(list); - } - }) -} - -require(scripts); diff --git a/node_modules/neataptic/docs/js/articles/classifycolors/neural.js b/node_modules/neataptic/docs/js/articles/classifycolors/neural.js deleted file mode 100644 index e851b89..0000000 --- a/node_modules/neataptic/docs/js/articles/classifycolors/neural.js +++ /dev/null @@ -1,106 +0,0 @@ -var Neat = neataptic.Neat; -var Methods = neataptic.Methods; -var Network = neataptic.Network; - -var set; -var neat; -var running = false; -var iteration = 0; - -var PER_COLOR = 50; -// Possible colors: red, orange, yellow, green, blue, purple, pink and monochrome -var COLORS = ['red', 'green', 'blue']; -var network; - -$( document ).ready(function(){ - set = createSet(); - visualiseSet(); -}); - -function createNeat(){ - network = new Network(3, COLORS.length); - /*neat = new Neat(3, COLORS.length, fitness, { - mutation: [ - Methods.Mutation.ADD_NODE, - Methods.Mutation.ADD_CONN, - Methods.Mutation.MOD_WEIGHT, - Methods.Mutation.MOD_BIAS, - Methods.Mutation.SUB_NODE, - Methods.Mutation.MOD_ACTIVATION - ], - mutationRate: 0.6, - elitism: 5, - popsize: 100, - });*/ -} - -function visualiseSet(){ - $('.set').empty(); - for(color in COLORS){ - $('.set').append('

                  ' + COLORS[color] + '

                  '); - } - - for(var item in set){ - item = set[item]; - $('.'+ item.color).append('
                  '); - } -} - -function visualiseGenomeSet(genome){ - $('.fittestset').empty(); - for(color in COLORS){ - $('.fittestset').append('

                  ' + COLORS[color] + '

                  '); - } - - for(var item in set){ - item = set[item]; - var output = genome.activate(item.input); - var max = Math.max.apply(null, output); - var color = COLORS[output.indexOf(max)]; - - $('.fittest'+ color).append('
                  '); - } -} - -function loop(){ - network.evolve(set, { - iterations: 1, - mutationRate: 0.6, - elisitm: 5, - popSize: 100, - mutation: Methods.Mutation.FFW, - cost: Methods.Cost.MSE - }); - - visualiseGenomeSet(network); - - $('.iteration').text(iteration); - $('.bestfitness').text(network.test(set).error); - - iteration++; - if(running) setTimeout(loop, 1); -} - -// Thanks to https://github.com/davidmerfield/randomColor !! -function createSet(){ - var set = []; - - for(index in COLORS){ - var color = COLORS[index]; - - var randomColors = randomColor({ hue : color, count: PER_COLOR, format: 'rgb'}); - - for(var random in randomColors){ - var rgb = randomColors[random]; - random = rgb.substring(4, rgb.length-1).replace(/ /g, '').split(','); - for(var y in random) random[y] = random[y]/255; - - var output = Array.apply(null, Array(COLORS.length)).map(Number.prototype.valueOf, 0); - output[index] = 1; - - set.push({ input: random, output: output, color: color, rgb: rgb}); - } - } - - return set; -} diff --git a/node_modules/neataptic/docs/js/articles/classifycolors/randomColor.js b/node_modules/neataptic/docs/js/articles/classifycolors/randomColor.js deleted file mode 100644 index b37969a..0000000 --- a/node_modules/neataptic/docs/js/articles/classifycolors/randomColor.js +++ /dev/null @@ -1,431 +0,0 @@ -// randomColor by David Merfield under the CC0 license -// https://github.com/davidmerfield/randomColor/ - -;(function(root, factory) { - - // Support AMD - if (typeof define === 'function' && define.amd) { - define([], factory); - - // Support CommonJS - } else if (typeof exports === 'object') { - var randomColor = factory(); - - // Support NodeJS & Component, which allow module.exports to be a function - if (typeof module === 'object' && module && module.exports) { - exports = module.exports = randomColor; - } - - // Support CommonJS 1.1.1 spec - exports.randomColor = randomColor; - - // Support vanilla script loading - } else { - root.randomColor = factory(); - } - -}(this, function() { - - // Seed to get repeatable colors - var seed = null; - - // Shared color dictionary - var colorDictionary = {}; - - // Populate the color dictionary - loadColorBounds(); - - var randomColor = function (options) { - - options = options || {}; - - // Check if there is a seed and ensure it's an - // integer. Otherwise, reset the seed value. - if (options.seed !== undefined && options.seed !== null && options.seed === parseInt(options.seed, 10)) { - seed = options.seed; - - // A string was passed as a seed - } else if (typeof options.seed === 'string') { - seed = stringToInteger(options.seed); - - // Something was passed as a seed but it wasn't an integer or string - } else if (options.seed !== undefined && options.seed !== null) { - throw new TypeError('The seed value must be an integer or string'); - - // No seed, reset the value outside. - } else { - seed = null; - } - - var H,S,B; - - // Check if we need to generate multiple colors - if (options.count !== null && options.count !== undefined) { - - var totalColors = options.count, - colors = []; - - options.count = null; - - while (totalColors > colors.length) { - - // Since we're generating multiple colors, - // incremement the seed. Otherwise we'd just - // generate the same color each time... - if (seed && options.seed) options.seed += 1; - - colors.push(randomColor(options)); - } - - options.count = totalColors; - - return colors; - } - - // First we pick a hue (H) - H = pickHue(options); - - // Then use H to determine saturation (S) - S = pickSaturation(H, options); - - // Then use S and H to determine brightness (B). - B = pickBrightness(H, S, options); - - // Then we return the HSB color in the desired format - return setFormat([H,S,B], options); - }; - - function pickHue (options) { - - var hueRange = getHueRange(options.hue), - hue = randomWithin(hueRange); - - // Instead of storing red as two seperate ranges, - // we group them, using negative numbers - if (hue < 0) {hue = 360 + hue;} - - return hue; - - } - - function pickSaturation (hue, options) { - - if (options.luminosity === 'random') { - return randomWithin([0,100]); - } - - if (options.hue === 'monochrome') { - return 0; - } - - var saturationRange = getSaturationRange(hue); - - var sMin = saturationRange[0], - sMax = saturationRange[1]; - - switch (options.luminosity) { - - case 'bright': - sMin = 55; - break; - - case 'dark': - sMin = sMax - 10; - break; - - case 'light': - sMax = 55; - break; - } - - return randomWithin([sMin, sMax]); - - } - - function pickBrightness (H, S, options) { - - var bMin = getMinimumBrightness(H, S), - bMax = 100; - - switch (options.luminosity) { - - case 'dark': - bMax = bMin + 20; - break; - - case 'light': - bMin = (bMax + bMin)/2; - break; - - case 'random': - bMin = 0; - bMax = 100; - break; - } - - return randomWithin([bMin, bMax]); - } - - function setFormat (hsv, options) { - - switch (options.format) { - - case 'hsvArray': - return hsv; - - case 'hslArray': - return HSVtoHSL(hsv); - - case 'hsl': - var hsl = HSVtoHSL(hsv); - return 'hsl('+hsl[0]+', '+hsl[1]+'%, '+hsl[2]+'%)'; - - case 'hsla': - var hslColor = HSVtoHSL(hsv); - var alpha = options.alpha || Math.random(); - return 'hsla('+hslColor[0]+', '+hslColor[1]+'%, '+hslColor[2]+'%, ' + alpha + ')'; - - case 'rgbArray': - return HSVtoRGB(hsv); - - case 'rgb': - var rgb = HSVtoRGB(hsv); - return 'rgb(' + rgb.join(', ') + ')'; - - case 'rgba': - var rgbColor = HSVtoRGB(hsv); - var alpha = options.alpha || Math.random(); - return 'rgba(' + rgbColor.join(', ') + ', ' + alpha + ')'; - - default: - return HSVtoHex(hsv); - } - - } - - function getMinimumBrightness(H, S) { - - var lowerBounds = getColorInfo(H).lowerBounds; - - for (var i = 0; i < lowerBounds.length - 1; i++) { - - var s1 = lowerBounds[i][0], - v1 = lowerBounds[i][1]; - - var s2 = lowerBounds[i+1][0], - v2 = lowerBounds[i+1][1]; - - if (S >= s1 && S <= s2) { - - var m = (v2 - v1)/(s2 - s1), - b = v1 - m*s1; - - return m*S + b; - } - - } - - return 0; - } - - function getHueRange (colorInput) { - - if (typeof parseInt(colorInput) === 'number') { - - var number = parseInt(colorInput); - - if (number < 360 && number > 0) { - return [number, number]; - } - - } - - if (typeof colorInput === 'string') { - - if (colorDictionary[colorInput]) { - var color = colorDictionary[colorInput]; - if (color.hueRange) {return color.hueRange;} - } - } - - return [0,360]; - - } - - function getSaturationRange (hue) { - return getColorInfo(hue).saturationRange; - } - - function getColorInfo (hue) { - - // Maps red colors to make picking hue easier - if (hue >= 334 && hue <= 360) { - hue-= 360; - } - - for (var colorName in colorDictionary) { - var color = colorDictionary[colorName]; - if (color.hueRange && - hue >= color.hueRange[0] && - hue <= color.hueRange[1]) { - return colorDictionary[colorName]; - } - } return 'Color not found'; - } - - function randomWithin (range) { - if (seed === null) { - return Math.floor(range[0] + Math.random()*(range[1] + 1 - range[0])); - } else { - //Seeded random algorithm from http://indiegamr.com/generate-repeatable-random-numbers-in-js/ - var max = range[1] || 1; - var min = range[0] || 0; - seed = (seed * 9301 + 49297) % 233280; - var rnd = seed / 233280.0; - return Math.floor(min + rnd * (max - min)); - } - } - - function HSVtoHex (hsv){ - - var rgb = HSVtoRGB(hsv); - - function componentToHex(c) { - var hex = c.toString(16); - return hex.length == 1 ? '0' + hex : hex; - } - - var hex = '#' + componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]); - - return hex; - - } - - function defineColor (name, hueRange, lowerBounds) { - - var sMin = lowerBounds[0][0], - sMax = lowerBounds[lowerBounds.length - 1][0], - - bMin = lowerBounds[lowerBounds.length - 1][1], - bMax = lowerBounds[0][1]; - - colorDictionary[name] = { - hueRange: hueRange, - lowerBounds: lowerBounds, - saturationRange: [sMin, sMax], - brightnessRange: [bMin, bMax] - }; - - } - - function loadColorBounds () { - - defineColor( - 'monochrome', - null, - [[0,0],[100,0]] - ); - - defineColor( - 'red', - [-26,18], - [[20,100],[30,92],[40,89],[50,85],[60,78],[70,70],[80,60],[90,55],[100,50]] - ); - - defineColor( - 'orange', - [19,46], - [[20,100],[30,93],[40,88],[50,86],[60,85],[70,70],[100,70]] - ); - - defineColor( - 'yellow', - [47,62], - [[25,100],[40,94],[50,89],[60,86],[70,84],[80,82],[90,80],[100,75]] - ); - - defineColor( - 'green', - [63,178], - [[30,100],[40,90],[50,85],[60,81],[70,74],[80,64],[90,50],[100,40]] - ); - - defineColor( - 'blue', - [179, 257], - [[20,100],[30,86],[40,80],[50,74],[60,60],[70,52],[80,44],[90,39],[100,35]] - ); - - defineColor( - 'purple', - [258, 282], - [[20,100],[30,87],[40,79],[50,70],[60,65],[70,59],[80,52],[90,45],[100,42]] - ); - - defineColor( - 'pink', - [283, 334], - [[20,100],[30,90],[40,86],[60,84],[80,80],[90,75],[100,73]] - ); - - } - - function HSVtoRGB (hsv) { - - // this doesn't work for the values of 0 and 360 - // here's the hacky fix - var h = hsv[0]; - if (h === 0) {h = 1;} - if (h === 360) {h = 359;} - - // Rebase the h,s,v values - h = h/360; - var s = hsv[1]/100, - v = hsv[2]/100; - - var h_i = Math.floor(h*6), - f = h * 6 - h_i, - p = v * (1 - s), - q = v * (1 - f*s), - t = v * (1 - (1 - f)*s), - r = 256, - g = 256, - b = 256; - - switch(h_i) { - case 0: r = v; g = t; b = p; break; - case 1: r = q; g = v; b = p; break; - case 2: r = p; g = v; b = t; break; - case 3: r = p; g = q; b = v; break; - case 4: r = t; g = p; b = v; break; - case 5: r = v; g = p; b = q; break; - } - - var result = [Math.floor(r*255), Math.floor(g*255), Math.floor(b*255)]; - return result; - } - - function HSVtoHSL (hsv) { - var h = hsv[0], - s = hsv[1]/100, - v = hsv[2]/100, - k = (2-s)*v; - - return [ - h, - Math.round(s*v / (k<1 ? k : 2-k) * 10000) / 100, - k/2 * 100 - ]; - } - - function stringToInteger (string) { - var total = 0 - for (var i = 0; i !== string.length; i++) { - if (total >= Number.MAX_SAFE_INTEGER) break; - total += string.charCodeAt(i) - } - return total - } - - return randomColor; -})); diff --git a/node_modules/neataptic/docs/js/articles/neuroevolution/events.js b/node_modules/neataptic/docs/js/articles/neuroevolution/events.js deleted file mode 100644 index 33a21e7..0000000 --- a/node_modules/neataptic/docs/js/articles/neuroevolution/events.js +++ /dev/null @@ -1,20 +0,0 @@ -$(document).on('click', '.panel div.clickable', function (e) { - var $this = $(this); //Heading - var $panel = $this.parent('.panel'); - var $panel_body = $panel.children('.panel-body'); - var $display = $panel_body.css('display'); - - if ($display == 'block') { - $panel_body.slideUp(); - } else if($display == 'none') { - $panel_body.slideDown(); - } -}); - -$(document).ready(function(e){ - var $classy = '.panel.autocollapse'; - - var $found = $($classy); - $found.find('.panel-body').hide(); - $found.removeClass($classy); -}); diff --git a/node_modules/neataptic/docs/js/articles/neuroevolution/graph.css b/node_modules/neataptic/docs/js/articles/neuroevolution/graph.css deleted file mode 100644 index e3c602d..0000000 --- a/node_modules/neataptic/docs/js/articles/neuroevolution/graph.css +++ /dev/null @@ -1,89 +0,0 @@ -.node { - cursor: move; - stroke-width: 1.5px; -} -.link { - fill: none; - stroke: #BDBDBD; - stroke-width: 1.5px; - opacity: 0.4; - marker-end: url(#end-arrow); -} -.label { - fill: #CCCCCC; - font-size: 9px; - text-anchor: middle; - cursor: move; - font-family: Arial; -} -#end-arrow{ - opacity: 0.4; -} -.INPUT{ - fill: #ff6666; - stroke: #ff4d4d; -} -.OUTPUT{ - fill : #ff8c66; - stroke: #ff794d; -} -.LOGISTIC{ - fill: #ffb366; - stroke: #ffa64d; -} -.TANH{ - fill: #ffd966; - stroke: #ffd24d; -} -.IDENTITY{ - fill: #ffff66; - stroke: #ffff4d; -} -.STEP{ - fill: #d9ff66; - stroke: #d2ff4d; -} -.RELU{ - fill: #b3ff66; - stroke: #a6ff4d; -} -.SOFTSIGN{ - fill: #8cff66; - stroke: #79ff4d; -} -.SINUSOID{ - fill: #66ff66; - stroke: #4dff4d; -} -.GAUSSIAN{ - fill: #66ff8c; - stroke: #4dff79; -} -.BENT_IDENTITY{ - fill: #66ffd9; - stroke: #4dffd2; -} -.BIPOLAR{ - fill: #66d9ff; - stroke: #4dd2ff; -} -.BIPOLAR_SIGMOID{ - fill: #66b3ff; - stroke: #4da6ff; -} -.HARD_TANH{ - fill: #668cff; - stroke: #4d79ff; -} -.ABSOLUTE{ - fill: #6666ff; - stroke: #4d4dff; -} -.GATE{ - fill: #003300; - stroke: #001a00; -} -.CONSTANT{ - fill: #ff00ff; - stroke: #e600e6; -} diff --git a/node_modules/neataptic/docs/js/articles/neuroevolution/graph.js b/node_modules/neataptic/docs/js/articles/neuroevolution/graph.js deleted file mode 100644 index 5b91958..0000000 --- a/node_modules/neataptic/docs/js/articles/neuroevolution/graph.js +++ /dev/null @@ -1,122 +0,0 @@ -var NODE_RADIUS = 7; -var REPEL_FORCE = 0; -var LINK_DISTANCE = 100; - -var drawGraph = function(graph, panel, width, height) { - var d3cola = cola.d3adaptor() - .avoidOverlaps(true) - .size([width, height]); - - var svg = d3.select(panel); - - d3.selectAll(panel + "> *").remove(); - - // define arrow markers for graph links - svg.append('svg:defs').append('svg:marker') - .attr('id', 'end-arrow') - .attr('viewBox', '0 -5 10 10') - .attr('refX', 6) - .attr('markerWidth', 4) - .attr('markerHeight', 4) - .attr('orient', 'auto') - .append('svg:path') - .attr('d', 'M0,-5L10,0L0,5') - - graph.nodes.forEach(function (v) { v.height = v.width = 2 * NODE_RADIUS; }); - - d3cola - .nodes(graph.nodes) - .links(graph.links) - //.constraints(graph.constraints) - .symmetricDiffLinkLengths(REPEL_FORCE) - .linkDistance(LINK_DISTANCE) - .start(10, 15, 20); - - var path = svg.selectAll(".link") - .data(graph.links) - .enter().append('svg:path') - .attr('class', 'link') - - path.append("title") - .text(function (d) { - var text = ""; - text += "Weight: " + Math.round(d.weight*1000)/1000 + "\n";; - text += "Source: " + d.source.id + "\n";; - text += "Target: " + d.target.id; - return text; - }); - - var node = svg.selectAll(".node") - .data(graph.nodes) - .enter().append("circle") - .attr("class", function(d){ - return "node " + d.name; - }) - .attr("r", function(d) { return NODE_RADIUS; }) - - .call(d3cola.drag); - - node.append("title") - .text(function (d){ - var text = ""; - text += "Activation: " + Math.round(d.activation*1000)/1000 + "\n"; - text += "Bias: " + Math.round(d.bias*1000)/1000 + "\n"; - text += "Position: " + d.id; - return text; - }); - - var label = svg.selectAll(".label") - .data(graph.nodes) - .enter().append("text") - .attr("class", "label") - .text(function (d){return '(' + d.index + ') ' + d.name; }) - .call(d3cola.drag) - - d3cola.on("tick", function () { - // draw directed edges with proper padding from node centers - path.attr('d', function (d) { - var deltaX = d.target.x - d.source.x, - deltaY = d.target.y - d.source.y, - dist = Math.sqrt(deltaX * deltaX + deltaY * deltaY), - normX = deltaX / dist, - normY = deltaY / dist; - - if(isNaN(normX)) normX = 0; - if(isNaN(normY)) normY = 0; - - sourcePadding = NODE_RADIUS, - targetPadding = NODE_RADIUS + 2, - sourceX = d.source.x + (sourcePadding * normX), - sourceY = d.source.y + (sourcePadding * normY), - targetX = d.target.x - (targetPadding * normX), - targetY = d.target.y - (targetPadding * normY); - - // Defaults for normal edge. - drx = 0, - dry = 0, - xRotation = 0, // degrees - largeArc = 0, // 1 or 0 - sweep = 1; // 1 or 0 - - // Self edge. - if (d.source.x === d.target.x && d.source.y === d.target.y) { - drx = dist; - dry = dist; - xRotation = -45; - largeArc = 1; - drx = 20; - dry = 20; - targetX = targetX + 1; - targetY = targetY + 1; - } - return 'M' + sourceX + ',' + sourceY + "A" + drx + "," + dry + " " + xRotation + "," + largeArc + "," + sweep + " " + targetX + ',' + targetY; - }); - - node.attr("cx", function (d) { return d.x; }) - .attr("cy", function (d) { return d.y; }) - - label - .attr("x", function (d) { return d.x + 10; }) - .attr("y", function (d) { return d.y - 10; }); - }); -}; diff --git a/node_modules/neataptic/docs/js/articles/neuroevolution/import.js b/node_modules/neataptic/docs/js/articles/neuroevolution/import.js deleted file mode 100644 index aba3db4..0000000 --- a/node_modules/neataptic/docs/js/articles/neuroevolution/import.js +++ /dev/null @@ -1,38 +0,0 @@ -var scripts = [ - { type: 'script', url: "https://wagenaartje.github.io/neataptic/cdn/1.2.22/neataptic.js"}, - { type: 'script', url: "https://cdnjs.cloudflare.com/ajax/libs/d3/3.0.0/d3.js"}, - { type: 'script', url: "../../js/articles/neuroevolution/webcola.js"}, - { type: 'script', url: "../../js/articles/neuroevolution/events.js"}, - { type: 'script', url: "../../js/articles/neuroevolution/graph.js"}, - { type: 'script', url: "../../js/articles/neuroevolution/neural.js"}, - { type: 'css', url: "../../js/articles/neuroevolution/graph.css"} -]; - -/** https://stackoverflow.com/questions/33330636/load-javascript-dynamically-and-sequentially **/ -function require(list) { - function loadScript(link) { - return new Promise(function(fulfill, reject) { - if(link.type == 'script'){ - var script = document.createElement("script"); - script.addEventListener("load", fulfill); - script.src = link.url; - document.head.appendChild(script); - } else if(link.type == 'css'){ - var stylesheet = document.createElement('link'); - stylesheet.addEventListener("load", fulfill); - stylesheet.rel = 'stylesheet'; - stylesheet.type = 'text/css'; - stylesheet.href = link.url; - stylesheet.media = "screen,print"; - document.head.appendChild(stylesheet); - } - }); - } - loadScript(list.shift()).then(function() { - if (list.length > 0) { - require(list); - } - }) -} - -require(scripts); diff --git a/node_modules/neataptic/docs/js/articles/neuroevolution/neural.js b/node_modules/neataptic/docs/js/articles/neuroevolution/neural.js deleted file mode 100644 index 837e58c..0000000 --- a/node_modules/neataptic/docs/js/articles/neuroevolution/neural.js +++ /dev/null @@ -1,165 +0,0 @@ -var Network = neataptic.Network; -var Methods = neataptic.Methods; -var Neat = neataptic.Neat; -var Config = neataptic.Config; - -Config.warnings = false; - -var examples = [ - { - set: [ - { input: [0.0], output: [0.2] }, - { input: [0.2], output: [0.4] }, - { input: [0.4], output: [0.6] }, - { input: [0.6], output: [0.8] }, - { input: [0.8], output: [1.0] }, - { input: [1.0], output: [0.8] }, - { input: [0.8], output: [0.6] }, - { input: [0.6], output: [0.4] }, - { input: [0.4], output: [0.2] }, - { input: [0.2], output: [0.0] } - ], - options: { - mutation: Methods.Mutation.ALL, - equal: true, - elitism: 5, - iterations: 1500, - clear: true, - error: 0.003 - } - }, - { - set: [ - { input: [0], output: [0] }, - { input: [0], output: [0] }, - { input: [0], output: [0] }, - { input: [0], output: [0] }, - { input: [0], output: [0] }, - { input: [0], output: [0] }, - { input: [0], output: [0] }, - { input: [0], output: [0] }, - { input: [0], output: [0] }, - { input: [0], output: [1] } - ], - options: { - mutation: Methods.Mutation.ALL, - equal: true, - elitism: 5, - iterations: 1500, - clear: true, - error: 0.003 - } - }, - { - set: [ - { input: [1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [1] }, // A - { input: [0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // B - { input: [0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // C - { input: [0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // D - { input: [0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [1] }, // E - { input: [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // F - { input: [0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // G - { input: [0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // H - { input: [0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [1] }, // I - { input: [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // J - { input: [0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // K - { input: [0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // L - { input: [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // M - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0], output: [0] }, // N - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0], output: [1] }, // O - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0], output: [0] }, // P - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0], output: [0] }, // Q - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0], output: [0] }, // R - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0], output: [0] }, // S - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0], output: [0] }, // T - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0], output: [1] }, // U - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0], output: [0] }, // V - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0], output: [0] }, // W - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0], output: [0] }, // X - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0], output: [0] }, // Y - { input: [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], output: [0] }, // Z - ], - options: { - mutation: Methods.Mutation.FFW, - equal: true, - elitism: 5, - iterations: 1500, - clear: true, - error: 0.001 - } - }, -] - -function showModal(id, type){ - if(type == 0){ - var set = examples[id-1].set; - var s = ''; - for(var i = 0; i < set.length; i++){ - var input = JSON.stringify(set[i].input); - var output = JSON.stringify(set[i].output); - s += (`Input: ${input}, output: ${output}\n`); - } - $('.modalcontent').html(s); - $('.modal-title').text('Training set'); - } else if(type == 1){ - var options = examples[id-1].options; - var keys = Object.keys(options); - var s = ''; - for(var i = 0; i < keys.length; i++){ - if(keys[i] == 'mutation'){ - var value = ''; - for(var j = 0; j < options[keys[i]].length; j++){ - value += options[keys[i]][j].name + ', '; - } - } else { - var value = options[keys[i]]; - } - s += (`${keys[i]}: ${value}\n`); - } - $('.modalcontent').html(s); - $('.modal-title').text('Evolve settings'); - } else if(type == 2){ - $('.modalcontent').html(examples[id-1].output); - $('.modal-title').text('Output'); - } - $('#modal').modal(); -} - -function run(id){ - var set = examples[id-1].set; - var options = examples[id-1].options; - - $('.status' + id).show(); - $('.status' + id).text('Running...'); - setTimeout(freeze, 10, id, set, options) -} - -function freeze(id, set, options){ - var network = new Network(set[0].input.length, set[0].output.length); - var results = network.evolve(set, options); - $('.example' + id).width('100%'); - $('.example' + id).height(400); - $('.example' + id).show(); - - var width = $('.example' + id).width(); - drawGraph(network.graph(width, 400), '.example' + id, width, 400); - - var s = ''; - for(var i = 0; i < set.length; i++){ - var input = JSON.stringify(set[i].input); - var targetoutput = JSON.stringify(set[i].output); - var output = network.activate(set[i].input); - - for(var j = 0; j < output.length; j++){ - output[j] = Math.round(output[j] * 1000) / 1000; - } - - output = JSON.stringify(output); - s += (`Input: ${input}, wanted output: ${targetoutput}, actual: ${output}\n`); - } - examples[id-1].output = s; - - $('.status' + id).text('Show outputs'); - $('.error' + id).text('Error ' + Math.round(-results.error * 1000) / 1000); - $('.error' + id).show(); -} diff --git a/node_modules/neataptic/docs/js/articles/neuroevolution/webcola.js b/node_modules/neataptic/docs/js/articles/neuroevolution/webcola.js deleted file mode 100644 index de31c48..0000000 --- a/node_modules/neataptic/docs/js/articles/neuroevolution/webcola.js +++ /dev/null @@ -1,3 +0,0 @@ -var cola;!function(a){var b=function(){function a(){this.locks={}}return a.prototype.add=function(a,b){isNaN(b[0])||isNaN(b[1]),this.locks[a]=b},a.prototype.clear=function(){this.locks={}},a.prototype.isEmpty=function(){for(var a in this.locks)return!1;return!0},a.prototype.apply=function(a){for(var b in this.locks)a(b,this.locks[b])},a}();a.Locks=b;var c=function(){function a(a,c,e){void 0===e&&(e=null),this.D=c,this.G=e,this.threshold=1e-4,this.random=new d,this.project=null,this.x=a,this.k=a.length;var f=this.n=a[0].length;this.H=new Array(this.k),this.g=new Array(this.k),this.Hd=new Array(this.k),this.a=new Array(this.k),this.b=new Array(this.k),this.c=new Array(this.k),this.d=new Array(this.k),this.e=new Array(this.k),this.ia=new Array(this.k),this.ib=new Array(this.k),this.xtmp=new Array(this.k),this.locks=new b,this.minD=Number.MAX_VALUE;for(var g,h=f;h--;)for(g=f;--g>h;){var i=c[h][g];i>0&&id;++d){c[d]=new Array(a);for(var e=0;a>e;++e)c[d][e]=b(d,e)}return c},a.prototype.offsetDir=function(){for(var a=this,b=new Array(this.k),c=0,d=0;dc)){for(var d,e=new Array(this.k),f=new Array(this.k),g=new Array(this.k),h=0,i=0;c>i;++i){for(d=0;dj;++j)if(i!==j){for(var k=c;k--;){var l=0;for(d=0;d1e-9)break;var n=this.offsetDir();for(d=0;d1&&o>p||!isFinite(p))for(d=0;d1&&(q=1);var r=p*p,s=q*(o-p)/(r*o),t=-q/(r*o*o*o);for(isFinite(s)||console.log(s),d=0;de;++e)c+=a.dotProd(this.g[e],b[e]),a.rightMultiply(this.H[e],b[e],this.Hd[e]),d+=a.dotProd(b[e],this.Hd[e]);return 0!==d&&isFinite(d)?c/d:0},a.prototype.reduceStress=function(){this.computeDerivatives(this.x);for(var a=this.computeStepSize(this.g),b=0;be;++e)for(var f=0;d>f;++f)b[e][f]=a[e][f]},a.prototype.stepAndProject=function(b,c,d,e){a.copy(b,c),this.takeDescentStep(c[0],d[0],e),this.project&&this.project[0](b[0],b[1],c[0]),this.takeDescentStep(c[1],d[1],e),this.project&&this.project[1](c[0],b[1],c[1])},a.mApply=function(a,b,c){for(var d=a;d-->0;)for(var e=b;e-->0;)c(d,e)},a.prototype.matrixApply=function(b){a.mApply(this.k,this.n,b)},a.prototype.computeNextPosition=function(a,b){var c=this;this.computeDerivatives(a);var d=this.computeStepSize(this.g);this.stepAndProject(a,b,this.g,d);for(var e=0;e0;){var d=this.rungeKutta();c=Math.abs(b/d-1)b;++b)for(var d=b+1,e=this.n;e>d;++d){for(var f=0,g=0;g>16)/this.range},a.prototype.getNextBetween=function(a,b){return a+this.getNext()*(b-a)},a}();a.PseudoRandom=d}(cola||(cola={}));var __extends=this.__extends||function(a,b){function c(){this.constructor=a}for(var d in b)b.hasOwnProperty(d)&&(a[d]=b[d]);c.prototype=b.prototype,a.prototype=new c},cola;!function(a){var b;!function(b){function c(a,b,c){return(b.x-a.x)*(c.y-a.y)-(c.x-a.x)*(b.y-a.y)}function d(a,b,d){return c(a,b,d)>0}function e(a,b,d){return c(a,b,d)<0}function f(a){var b,d=a.slice(0).sort(function(a,b){return a.x!==b.x?b.x-a.x:b.y-a.y}),e=a.length,f=0,g=d[0].x;for(b=1;e>b&&d[b].x===g;++b);var h=b-1,i=[];if(i.push(d[f]),h===e-1)d[h].y!==d[f].y&&i.push(d[h]);else{var j,k=e-1,l=d[e-1].x;for(b=e-2;b>=0&&d[b].x===l;b--);for(j=b+1,b=h;++b<=j;)if(!(c(d[f],d[j],d[b])>=0&&j>b)){for(;i.length>1&&!(c(i[i.length-2],i[i.length-1],d[b])>0);)i.length-=1;b!=f&&i.push(d[b])}k!=j&&i.push(d[k]);var m=i.length;for(b=j;--b>=h;)if(!(c(d[k],d[h],d[b])>=0&&b>h)){for(;i.length>m&&!(c(i[i.length-2],i[i.length-1],d[b])>0);)i.length-=1;b!=f&&i.push(d[b])}}return i}function g(a,b,c){b.slice(0).sort(function(b,c){return Math.atan2(b.y-a.y,b.x-a.x)-Math.atan2(c.y-a.y,c.x-a.x)}).forEach(c)}function h(a,b){return{rtan:i(a,b),ltan:j(a,b)}}function i(a,b){var c,f,g,h,i,j=b.length-1;if(e(a,b[1],b[0])&&!d(a,b[j-1],b[0]))return 0;for(c=0,f=j;;){if(f-c===1)return d(a,b[c],b[f])?c:f;if(g=Math.floor((c+f)/2),i=e(a,b[g+1],b[g]),i&&!d(a,b[g-1],b[g]))return g;h=d(a,b[c+1],b[c]),h?i?f=g:d(a,b[c],b[g])?f=g:c=g:i&&e(a,b[c],b[g])?f=g:c=g}}function j(a,b){var c,f,g,h,i,j=b.length-1;if(d(a,b[j-1],b[0])&&!e(a,b[1],b[0]))return 0;for(c=0,f=j;;){if(f-c===1)return e(a,b[c],b[f])?c:f;if(g=Math.floor((c+f)/2),i=e(a,b[g+1],b[g]),d(a,b[g-1],b[g])&&!i)return g;h=e(a,b[c+1],b[c]),h?i?e(a,b[c],b[g])?f=g:c=g:f=g:i?c=g:d(a,b[c],b[g])?f=g:c=g}}function k(a,b,c,d,e,f){var g,h;g=c(b[0],a),h=d(a[g],b);for(var i=!1;!i;){for(i=!0;;){if(g===a.length-1&&(g=0),e(b[h],a[g],a[g+1]))break;++g}for(;;){if(0===h&&(h=b.length-1),f(a[g],b[h],b[h-1]))break;--h,i=!1}}return{t1:g,t2:h}}function l(a,b){var c=m(b,a);return{t1:c.t2,t2:c.t1}}function m(a,b){return k(a,b,i,j,d,e)}function n(a,b){return k(a,b,j,j,e,e)}function o(a,b){return k(a,b,i,i,d,d)}function p(b,c){for(var d=[],e=1,f=c.length;f>e;++e){var g=a.vpsc.Rectangle.lineIntersection(b.x1,b.y1,b.x2,b.y2,c[e-1].x,c[e-1].y,c[e].x,c[e].y);g&&d.push(g)}return d}function q(a,b){for(var d=a.length-1,e=b.length-1,f=new y,g=0;d>g;++g)for(var h=0;e>h;++h){var i=a[0==g?d-1:g-1],j=a[g],k=a[g+1],l=b[0==h?e-1:h-1],m=b[h],n=b[h+1],o=c(i,j,m),p=c(j,l,m),q=c(j,m,n),r=c(l,m,j),s=c(m,i,j),t=c(m,j,k);o>=0&&p>=0&&0>q&&r>=0&&s>=0&&0>t?f.ll=new x(g,h):0>=o&&0>=p&&q>0&&0>=r&&0>=s&&t>0?f.rr=new x(g,h):0>=o&&p>0&&0>=q&&r>=0&&0>s&&t>=0?f.rl=new x(g,h):o>=0&&0>p&&q>=0&&0>=r&&s>0&&0>=t&&(f.lr=new x(g,h))}return f}function r(a,b){for(var c=1,d=b.length;d>c;++c)if(e(b[c-1],b[c],a))return!1;return!0}function s(a,b){return!a.every(function(a){return!r(a,b)})}function t(a,b){if(s(a,b))return!0;if(s(b,a))return!0;for(var c=1,d=a.length;d>c;++c){var e=a[c],f=a[c-1];if(p(new v(f.x,f.y,e.x,e.y),b).length>0)return!0}return!1}var u=function(){function a(){}return a}();b.Point=u;var v=function(){function a(a,b,c,d){this.x1=a,this.y1=b,this.x2=c,this.y2=d}return a}();b.LineSegment=v;var w=function(a){function b(){a.apply(this,arguments)}return __extends(b,a),b}(u);b.PolyPoint=w,b.isLeft=c,b.ConvexHull=f,b.clockwiseRadialSweep=g,b.tangent_PolyPolyC=k,b.LRtangent_PolyPolyC=l,b.RLtangent_PolyPolyC=m,b.LLtangent_PolyPolyC=n,b.RRtangent_PolyPolyC=o;var x=function(){function a(a,b){this.t1=a,this.t2=b}return a}();b.BiTangent=x;var y=function(){function a(){}return a}();b.BiTangents=y;var z=function(a){function b(){a.apply(this,arguments)}return __extends(b,a),b}(u);b.TVGPoint=z;var A=function(){function a(a,b,c,d){this.id=a,this.polyid=b,this.polyvertid=c,this.p=d,d.vv=this}return a}();b.VisibilityVertex=A;var B=function(){function a(a,b){this.source=a,this.target=b}return a.prototype.length=function(){var a=this.source.p.x-this.target.p.x,b=this.source.p.y-this.target.p.y;return Math.sqrt(a*a+b*b)},a}();b.VisibilityEdge=B;var C=function(){function a(a,c){if(this.P=a,this.V=[],this.E=[],c)this.V=c.V.slice(0),this.E=c.E.slice(0);else{for(var d=a.length,e=0;d>e;e++)for(var f=a[e],g=0;g0&&this.E.push(new B(f[g-1].vv,i))}for(var e=0;d-1>e;e++)for(var j=a[e],g=e+1;d>g;g++){var k=a[g],l=b.tangents(j,k);for(var m in l){var n=l[m],o=j[n.t1],p=k[n.t2];this.addEdgeIfVisible(o,p,e,g)}}}}return a.prototype.addEdgeIfVisible=function(a,b,c,d){this.intersectsPolys(new v(a.x,a.y,b.x,b.y),c,d)||this.E.push(new B(a.vv,b.vv))},a.prototype.addPoint=function(a,b){var c=this.P.length;this.V.push(new A(this.V.length,c,0,a));for(var d=0;c>d;++d)if(d!==b){var e=this.P[d],f=h(a,e);this.addEdgeIfVisible(a,e[f.ltan],b,d),this.addEdgeIfVisible(a,e[f.rtan],b,d)}return a.vv},a.prototype.intersectsPolys=function(a,b,c){for(var d=0,e=this.P.length;e>d;++d)if(d!=b&&d!=c&&p(a,this.P[d]).length>0)return!0;return!1},a}();b.TangentVisibilityGraph=C,b.tangents=q,b.polysOverlap=t}(b=a.geom||(a.geom={}))}(cola||(cola={}));var cola;!function(a){var b;!function(a){var b=function(){function a(a){this.scale=a,this.AB=0,this.AD=0,this.A2=0}return a.prototype.addVariable=function(a){var b=this.scale/a.scale,c=a.offset/a.scale,d=a.weight;this.AB+=d*b*c,this.AD+=d*b*a.desiredPosition,this.A2+=d*b*b},a.prototype.getPosn=function(){return(this.AD-this.AB)/this.A2},a}();a.PositionStats=b;var c=function(){function a(a,b,c,d){void 0===d&&(d=!1),this.left=a,this.right=b,this.gap=c,this.equality=d,this.active=!1,this.unsatisfiable=!1,this.left=a,this.right=b,this.gap=c,this.equality=d}return a.prototype.slack=function(){return this.unsatisfiable?Number.MAX_VALUE:this.right.scale*this.right.position()-this.gap-this.left.scale*this.left.position()},a}();a.Constraint=c;var d=function(){function a(a,b,c){void 0===b&&(b=1),void 0===c&&(c=1),this.desiredPosition=a,this.weight=b,this.scale=c,this.offset=0}return a.prototype.dfdv=function(){return 2*this.weight*(this.position()-this.desiredPosition)},a.prototype.position=function(){return(this.block.ps.scale*this.block.posn+this.offset)/this.scale},a.prototype.visitNeighbours=function(a,b){var c=function(c,d){return c.active&&a!==d&&b(c,d)};this.cOut.forEach(function(a){return c(a,a.right)}),this.cIn.forEach(function(a){return c(a,a.left)})},a}();a.Variable=d;var e=function(){function a(a){this.vars=[],a.offset=0,this.ps=new b(a.scale),this.addVariable(a)}return a.prototype.addVariable=function(a){a.block=this,this.vars.push(a),this.ps.addVariable(a),this.posn=this.ps.getPosn()},a.prototype.updateWeightedPosition=function(){this.ps.AB=this.ps.AD=this.ps.A2=0;for(var a=0,b=this.vars.length;b>a;++a)this.ps.addVariable(this.vars[a]);this.posn=this.ps.getPosn()},a.prototype.compute_lm=function(a,b,c){var d=this,e=a.dfdv();return a.visitNeighbours(b,function(b,f){var g=d.compute_lm(f,a,c);f===b.right?(e+=g*b.left.scale,b.lm=g):(e+=g*b.right.scale,b.lm=-g),c(b)}),e/a.scale},a.prototype.populateSplitBlock=function(a,b){var c=this;a.visitNeighbours(b,function(b,d){d.offset=a.offset+(d===b.right?b.gap:-b.gap),c.addVariable(d),c.populateSplitBlock(d,a)})},a.prototype.traverse=function(a,b,c,d){var e=this;void 0===c&&(c=this.vars[0]),void 0===d&&(d=null),c.visitNeighbours(d,function(d,f){b.push(a(d)),e.traverse(a,b,f,c)})},a.prototype.findMinLM=function(){var a=null;return this.compute_lm(this.vars[0],null,function(b){!b.equality&&(null===a||b.lmd;++d){var f=a.vars[d];f.offset+=c,this.addVariable(f)}this.posn=this.ps.getPosn()},a.prototype.cost=function(){for(var a=0,b=this.vars.length;b--;){var c=this.vars[b],d=c.position()-c.desiredPosition;a+=d*d*c.weight}return a},a}();a.Block=e;var f=function(){function a(a){this.vs=a;var b=a.length;for(this.list=new Array(b);b--;){var c=new e(a[b]);this.list[b]=c,c.blockInd=b}}return a.prototype.cost=function(){for(var a=0,b=this.list.length;b--;)a+=this.list[b].cost();return a},a.prototype.insert=function(a){a.blockInd=this.list.length,this.list.push(a)},a.prototype.remove=function(a){var b=this.list.length-1,c=this.list[b];this.list.length=b,a!==c&&(this.list[a.blockInd]=c,c.blockInd=a.blockInd)},a.prototype.merge=function(a){var b=a.left.block,c=a.right.block,d=a.right.offset-a.left.offset-a.gap;b.vars.lengthg;++g){var h=d[g];if(!h.unsatisfiable){var i=h.slack();if((h.equality||b>i)&&(b=i,c=h,f=g,h.equality))break}}return f!==e&&(b=0?this.inactive.push(b):this.bs.merge(b)}}},a.prototype.solve=function(){this.satisfy();for(var a=Number.MAX_VALUE,b=this.bs.cost();Math.abs(a-b)>1e-4;)this.satisfy(),a=b,b=this.bs.cost();return b},a.LAGRANGIAN_TOLERANCE=-1e-4,a.ZERO_UPPERBOUND=-1e-10,a}();a.Solver=g}(b=a.vpsc||(a.vpsc={}))}(cola||(cola={}));var cola;!function(a){var b;!function(a){function b(a){return a.bounds="undefined"!=typeof a.leaves?a.leaves.reduce(function(a,b){return b.bounds.union(a)},p.empty()):p.empty(),"undefined"!=typeof a.groups&&(a.bounds=a.groups.reduce(function(a,c){return b(c).union(a)},a.bounds)),a.bounds=a.bounds.inflate(a.padding),a.bounds}function c(a,b,c,d){var e=b.rayIntersection(c.cx(),c.cy());e||(e={x:b.cx(),y:b.cy()});var f=c.rayIntersection(b.cx(),b.cy());f||(f={x:c.cx(),y:c.cy()});var g=f.x-e.x,h=f.y-e.y,i=Math.sqrt(g*g+h*h),j=i-d;a.sourceIntersection=e,a.targetIntersection=f,a.arrowStart={x:e.x+j*g/i,y:e.y+j*h/i}}function d(a,b,c){var d=b.rayIntersection(a.x,a.y);d||(d={x:b.cx(),y:b.cy()});var e=d.x-a.x,f=d.y-a.y,g=Math.sqrt(e*e+f*f);return{x:d.x-c*e/g,y:d.y-c*f/g}}function e(a,b){return a.pos>b.pos?1:a.pos=i);var k=new Array(j);for(h=0;i>h;++h){var l=b[h],m=new q(c[h],l,d.getCentre(l));k[h]=new r(!0,m,d.getOpen(l)),k[h+i]=new r(!1,m,d.getClose(l))}k.sort(e);var n=new Array,o=f();for(h=0;j>h;++h){var p=k[h],m=p.v;if(p.isOpen)o.insert(m),d.findNeighbours(m,o);else{o.remove(m);var s=function(b,c){var e=(d.getSize(b.r)+d.getSize(c.r))/2+g;n.push(new a.Constraint(b.v,c.v,e))},t=function(a,b,c){for(var d,e=m[a].iterator();null!==(d=e[a]());)c(d,m),d[b].remove(m)};t("prev","next",function(a,b){return s(a,b)}),t("next","prev",function(a,b){return s(b,a)})}}return console.assert(0===o.size),n}function i(a,b){var c=function(c,d){for(var e,f=b.findIter(a);null!==(e=f[c]());){var g=e.r.overlapX(a.r);if((0>=g||g<=e.r.overlapY(a.r))&&(a[c].insert(e),e[d].insert(a)),0>=g)break}};c("next","prev"),c("prev","next")}function j(a,b){var c=function(c,d){var e=b.findIter(a)[c]();null!==e&&e.r.overlapX(a.r)>0&&(a[c].insert(e),e[d].insert(a))};c("next","prev"),c("prev","next")}function k(a,b){return h(a,b,s,1e-6)}function l(a,b){return h(a,b,t,1e-6)}function m(a){return g(a,s,1e-6)}function n(a){return g(a,t,1e-6)}function o(b){var c=b.map(function(b){return new a.Variable(b.cx())}),d=a.generateXConstraints(b,c),e=new a.Solver(c,d);e.solve(),c.forEach(function(a,c){return b[c].setXCentre(a.position())}),c=b.map(function(b){return new a.Variable(b.cy())}),d=a.generateYConstraints(b,c),e=new a.Solver(c,d),e.solve(),c.forEach(function(a,c){return b[c].setYCentre(a.position())})}a.computeGroupBounds=b;var p=function(){function a(a,b,c,d){this.x=a,this.X=b,this.y=c,this.Y=d}return a.empty=function(){return new a(Number.POSITIVE_INFINITY,Number.NEGATIVE_INFINITY,Number.POSITIVE_INFINITY,Number.NEGATIVE_INFINITY)},a.prototype.cx=function(){return(this.x+this.X)/2},a.prototype.cy=function(){return(this.y+this.Y)/2},a.prototype.overlapX=function(a){var b=this.cx(),c=a.cx();return c>=b&&a.x=c&&this.x=b&&a.y=c&&this.yh;++h){var i=a.lineIntersection(b,c,d,e,f[h][0],f[h][1],f[h][2],f[h][3]);null!==i&&g.push({x:i.x,y:i.y})}return g},a.prototype.rayIntersection=function(a,b){var c=this.lineIntersections(this.cx(),this.cy(),a,b);return c.length>0?c[0]:null},a.prototype.vertices=function(){return[{x:this.x,y:this.y},{x:this.X,y:this.y},{x:this.X,y:this.Y},{x:this.x,y:this.Y},{x:this.x,y:this.y}]},a.lineIntersection=function(a,b,c,d,e,f,g,h){var i=c-a,j=g-e,k=d-b,l=h-f,m=l*i-j*k;if(0==m)return null;var n=a-e,o=b-f,p=j*o-l*n,q=p/m,r=i*o-k*n,s=r/m;return q>=0&&1>=q&&s>=0&&1>=s?{x:a+q*i,y:b+q*k}:null},a.prototype.inflate=function(b){return new a(this.x-b,this.X+b,this.y-b,this.Y+b)},a}();a.Rectangle=p,a.makeEdgeBetween=c,a.makeEdgeTo=d;var q=function(){function a(a,b,c){this.v=a,this.r=b,this.pos=c,this.prev=f(),this.next=f()}return a}(),r=function(){function a(a,b,c){this.isOpen=a,this.v=b,this.pos=c}return a}(),s={getCentre:function(a){return a.cx()},getOpen:function(a){return a.y},getClose:function(a){return a.Y},getSize:function(a){return a.width()},makeRect:function(a,b,c,d){return new p(c-d/2,c+d/2,a,b)},findNeighbours:i},t={getCentre:function(a){return a.cy()},getOpen:function(a){return a.x},getClose:function(a){return a.X},getSize:function(a){return a.height()},makeRect:function(a,b,c,d){return new p(a,b,c-d/2,c+d/2)},findNeighbours:j};a.generateXConstraints=k,a.generateYConstraints=l,a.generateXGroupConstraints=m,a.generateYGroupConstraints=n,a.removeOverlaps=o;var u=function(a){function b(b,c){a.call(this,0,c),this.index=b}return __extends(b,a),b}(a.Variable),v=function(){function c(c,d,e,f,g){var h=this;if(void 0===e&&(e=null),void 0===f&&(f=null),void 0===g&&(g=!1),this.nodes=c,this.groups=d,this.rootGroup=e,this.avoidOverlaps=g,this.variables=c.map(function(a,b){return a.variable=new u(b,1)}),f&&this.createConstraints(f),g&&e&&"undefined"!=typeof e.groups){c.forEach(function(b){if(!b.width||!b.height)return void(b.bounds=new a.Rectangle(b.x,b.x,b.y,b.y));var c=b.width/2,d=b.height/2;b.bounds=new a.Rectangle(b.x-c,b.x+c,b.y-d,b.y+d)}),b(e);var i=c.length;d.forEach(function(a){h.variables[i]=a.minVar=new u(i++,.01),h.variables[i]=a.maxVar=new u(i++,.01)})}}return c.prototype.createSeparation=function(b){return new a.Constraint(this.nodes[b.left].variable,this.nodes[b.right].variable,b.gap,"undefined"!=typeof b.equality?b.equality:!1)},c.prototype.makeFeasible=function(a){var b=this;if(this.avoidOverlaps){var c="x",d="width";"x"===a.axis&&(c="y",d="height");var e=a.offsets.map(function(a){return b.nodes[a.node]}).sort(function(a,b){return a[c]-b[c]}),f=null;e.forEach(function(a){f&&(a[c]=f[c]+f[d]+1),f=a})}},c.prototype.createAlignment=function(b){var c=this,d=this.nodes[b.offsets[0].node].variable;this.makeFeasible(b);var e="x"===b.axis?this.xConstraints:this.yConstraints;b.offsets.slice(1).forEach(function(b){var f=c.nodes[b.node].variable;e.push(new a.Constraint(d,f,b.offset,!0))})},c.prototype.createConstraints=function(a){var b=this,c=function(a){return"undefined"==typeof a.type||"separation"===a.type};this.xConstraints=a.filter(function(a){return"x"===a.axis&&c(a)}).map(function(a){return b.createSeparation(a)}),this.yConstraints=a.filter(function(a){return"y"===a.axis&&c(a)}).map(function(a){return b.createSeparation(a)}),a.filter(function(a){return"alignment"===a.type}).forEach(function(a){return b.createAlignment(a)})},c.prototype.setupVariablesAndBounds=function(a,b,c,d){this.nodes.forEach(function(e,f){e.fixed?(e.variable.weight=1e3,c[f]=d(e)):e.variable.weight=1;var g=(e.width||0)/2,h=(e.height||0)/2,i=a[f],j=b[f];e.bounds=new p(i-g,i+g,j-h,j+h)})},c.prototype.xProject=function(a,b,c){(this.rootGroup||this.avoidOverlaps||this.xConstraints)&&this.project(a,b,a,c,function(a){return a.px},this.xConstraints,m,function(a){return a.bounds.setXCentre(c[a.variable.index]=a.variable.position())},function(a){var b=c[a.minVar.index]=a.minVar.position(),d=c[a.maxVar.index]=a.maxVar.position(),e=a.padding/2;a.bounds.x=b-e,a.bounds.X=d+e})},c.prototype.yProject=function(a,b,c){(this.rootGroup||this.yConstraints)&&this.project(a,b,b,c,function(a){return a.py},this.yConstraints,n,function(a){return a.bounds.setYCentre(c[a.variable.index]=a.variable.position())},function(a){var b=c[a.minVar.index]=a.minVar.position(),d=c[a.maxVar.index]=a.maxVar.position(),e=a.padding/2;a.bounds.y=b-e,a.bounds.Y=d+e})},c.prototype.projectFunctions=function(){var a=this;return[function(b,c,d){return a.xProject(b,c,d)},function(b,c,d){return a.yProject(b,c,d)}]},c.prototype.project=function(a,c,d,e,f,g,h,i,j){this.setupVariablesAndBounds(a,c,e,f),this.rootGroup&&this.avoidOverlaps&&(b(this.rootGroup),g=g.concat(h(this.rootGroup))),this.solve(this.variables,g,d,e),this.nodes.forEach(i),this.rootGroup&&this.avoidOverlaps&&this.groups.forEach(j)},c.prototype.solve=function(b,c,d,e){var f=new a.Solver(b,c);f.setStartingPositions(d),f.setDesiredPositions(e),f.solve()},c}();a.Projection=v}(b=a.vpsc||(a.vpsc={}))}(cola||(cola={}));var PairingHeap=function(){function a(a){this.elem=a,this.subheaps=[]}return a.prototype.toString=function(a){for(var b="",c=!1,d=0;dk&&(i.d=k,i.prev=g,c.reduceKey(i.q,i,function(a,b){return a.q=b}))}}return e},a}();a.Calculator=e}(b=a.shortestpaths||(a.shortestpaths={}))}(cola||(cola={}));var cola;!function(a){var b=function(){function a(a,b,c){this.id=a,this.rect=b,this.children=c,this.leaf="undefined"==typeof c||0===c.length}return a}();a.NodeWrapper=b;var c=function(){function a(a,b,c,d,e){void 0===d&&(d=null),void 0===e&&(e=null),this.id=a,this.x=b,this.y=c,this.node=d,this.line=e}return a}();a.Vert=c;var d=function(){function a(b,c){this.s=b,this.t=c;var d=a.findMatch(b,c),e=c.slice(0).reverse(),f=a.findMatch(b,e);d.length>=f.length?(this.length=d.length,this.si=d.si,this.ti=d.ti,this.reversed=!1):(this.length=f.length,this.si=f.si,this.ti=c.length-f.ti-f.length,this.reversed=!0)}return a.findMatch=function(a,b){for(var c=a.length,d=b.length,e={length:0,si:-1,ti:-1},f=new Array(c),g=0;c>g;g++){f[g]=new Array(d);for(var h=0;d>h;h++)if(a[g]===b[h]){var i=f[g][h]=0===g||0===h?1:f[g-1][h-1]+1;i>e.length&&(e.length=i,e.si=g-i+1,e.ti=h-i+1)}else f[g][h]=0}return e},a.prototype.getSequence=function(){return this.length>=0?this.s.slice(this.si,this.si+this.length):[]},a}();a.LongestCommonSubsequence=d; -var e=function(){function d(d,e,f){var g=this;void 0===f&&(f=12),this.originalnodes=d,this.groupPadding=f,this.leaves=null,this.nodes=d.map(function(a,c){return new b(c,e.getBounds(a),e.getChildren(a))}),this.leaves=this.nodes.filter(function(a){return a.leaf}),this.groups=this.nodes.filter(function(a){return!a.leaf}),this.cols=this.getGridDim("x"),this.rows=this.getGridDim("y"),this.groups.forEach(function(a){return a.children.forEach(function(b){return g.nodes[b].parent=a})}),this.root={children:[]},this.nodes.forEach(function(a){"undefined"==typeof a.parent&&(a.parent=g.root,g.root.children.push(a.id)),a.ports=[]}),this.backToFront=this.nodes.slice(0),this.backToFront.sort(function(a,b){return g.getDepth(a)-g.getDepth(b)});var h=this.backToFront.slice(0).reverse().filter(function(a){return!a.leaf});h.forEach(function(b){var c=a.vpsc.Rectangle.empty();b.children.forEach(function(a){return c=c.union(g.nodes[a].rect)}),b.rect=c.inflate(g.groupPadding)});var i=this.midPoints(this.cols.map(function(a){return a.x})),j=this.midPoints(this.rows.map(function(a){return a.y})),k=i[0],l=i[i.length-1],m=j[0],n=j[j.length-1],o=this.rows.map(function(a){return{x1:k,x2:l,y1:a.y,y2:a.y}}).concat(j.map(function(a){return{x1:k,x2:l,y1:a,y2:a}})),p=this.cols.map(function(a){return{x1:a.x,x2:a.x,y1:m,y2:n}}).concat(i.map(function(a){return{x1:a,x2:a,y1:m,y2:n}})),q=o.concat(p);q.forEach(function(a){return a.verts=[]}),this.verts=[],this.edges=[],o.forEach(function(a){return p.forEach(function(b){var d=new c(g.verts.length,b.x1,a.y1);a.verts.push(d),b.verts.push(d),g.verts.push(d);for(var e=g.backToFront.length;e-->0;){var f=g.backToFront[e],h=f.rect,i=Math.abs(d.x-h.cx()),j=Math.abs(d.y-h.cy());if(i0;){var d=c[0].rect,e=c.filter(function(b){return b.rect["overlap"+a.toUpperCase()](d)});b.push(e),e.forEach(function(a){return c.splice(c.indexOf(a),1)}),e[a]=this.avg(e.map(function(b){return b.rect["c"+a]()}))}return b.sort(function(b,c){return b[a]-c[a]}),b},d.prototype.getDepth=function(a){for(var b=0;a.parent!==this.root;)b++,a=a.parent;return b},d.prototype.midPoints=function(a){for(var b=a[1]-a[0],c=[a[0]-b/2],d=1;d.1)&&(j={pos:g[0][b],segments:[]},i.push(j)),j.segments.push(g)}return i},d.nudgeSegs=function(b,c,d,e,f,g){var h=e.length;if(!(1>=h)){for(var i=e.map(function(c){return new a.vpsc.Variable(c[0][b])}),j=[],k=0;h>k;k++)for(var l=0;h>l;l++)if(k!==l){var m=e[k],n=e[l],o=m.edgeid,p=n.edgeid,q=-1,r=-1;"x"==b?f(o,p)&&(m[0][c]=0&&j.push(new a.vpsc.Constraint(i[q],i[r],g))}var s=new a.vpsc.Solver(i,j);s.solve(),i.forEach(function(a,c){var f=e[c],g=a.position();f[0][b]=f[1][b]=g;var h=d[f.edgeid];f.i>0&&(h[f.i-1][1][b]=g),f.iMath.PI||e<-Math.PI)&&(e=d-c),e},d.isLeft=function(a,b,c){return(b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x)<=0},d.getOrder=function(a){for(var b={},c=0;c=j.length||l.ti+l.length>=k.length?(g=j[l.si+1],i=j[l.si-1],h=k[l.ti-1]):(g=j[l.si+l.length-2],h=j[l.si+l.length],i=k[l.ti+l.length]),c.push(d.isLeft(g,h,i)?{l:f,r:e}:{l:e,r:f})):c.push({l:e,r:f}))}return a.GridRouter.getOrder(c)},d.makeSegments=function(a){function b(a){return{x:a.x,y:a.y}}for(var c=function(a,b,c){return Math.abs((b.x-a.x)*(c.y-a.y)-(b.y-a.y)*(c.x-a.x))<.001},d=[],e=b(a[0]),f=1;f1&&k>1?1e3:0},p=n.PathFromNodeToNodeWithPrevCost(e.ports[0].id,f.ports[0].id,o),q=p.reverse().map(function(a){return d.verts[a]});return q.push(this.nodes[f.id].ports[0]),q.filter(function(a,b){return!(b0&&a.node===f&&q[b-1].node===f)})},d}();a.GridRouter=e}(cola||(cola={}));var cola;!function(a){function b(a,b){var c={};for(var d in a)c[d]={};for(var d in b)c[d]={};return Object.keys(c).length}function c(a,b){var c=0;for(var d in a)"undefined"!=typeof b[d]&&++c;return c}function d(a,b){var c={},d=function(a,b){"undefined"==typeof c[a]&&(c[a]={}),c[a][b]={}};return a.forEach(function(a){var c=b.getSourceIndex(a),e=b.getTargetIndex(a);d(c,e),d(e,c)}),c}function e(a,b,c,e){var f=d(a,e);a.forEach(function(a){var d=f[e.getSourceIndex(a)],g=f[e.getTargetIndex(a)];e.setLength(a,1+b*c(d,g))})}function f(a,d,f){void 0===f&&(f=1),e(a,f,function(a,d){return Math.sqrt(b(a,d)-c(a,d))},d)}function g(a,d,f){void 0===f&&(f=1),e(a,f,function(a,d){return Math.min(Object.keys(a).length,Object.keys(d).length)<1.1?0:c(a,d)/b(a,d)},d)}function h(a,b,c,d){var e=i(a,b,d),f={};e.filter(function(a){return a.length>1}).forEach(function(a){return a.forEach(function(b){return f[b]=a})});var g=[];return b.forEach(function(a){var b=d.getSourceIndex(a),e=d.getTargetIndex(a),h=f[b],i=f[e];h&&i&&h.component===i.component||g.push({axis:c,left:b,right:e,gap:d.getMinSeparation(a)})}),g}function i(a,b,c){function d(a){f[a]=j,g[a]=j,h[a]=!0,j+=1,k.push(a);for(var b=e[a],c=0;c=0;--c){var n=k[c];if(h[n]=!1,m.push(n),n===a){k.length=c;break}}l.push(m)}}for(var e=new Array(a),f=new Array(a),g=new Array(a),h=new Array(a),i=0;a>i;++i)e[i]=[],f[i]=-1,g[i]=0,h[i]=!1;for(var i=0;ii;++i)f[i]<0&&d(i);return l}a.symmetricDiffLinkLengths=f,a.jaccardLinkLengths=g,a.generateDirectedEdgeConstraints=h}(cola||(cola={}));var cola;!function(a){var b;!function(a){function b(a,c,d){a.forAll(function(a){if(a.isLeaf())c.leaves||(c.leaves=[]),c.leaves.push(a.id);else{var e=c;a.gid=d.length,(!a.isIsland()||a.predefined)&&(e={id:a.gid},c.groups||(c.groups=[]),c.groups.push(a.gid),d.push(e)),b(a.children,e,d)}})}function c(a,b){var c={};for(var d in a)d in b&&(c[d]=a[d]);return c}function d(b,c,d,e){for(var f=b.length,g=new a.Configuration(f,c,d,e);g.greedyMerge(););var h=[],i=g.getGroupHierarchy(h);return h.forEach(function(a){var c=function(c){var d=a[c];"number"==typeof d&&(a[c]=b[d])};c("source"),c("target")}),{groups:i,powerEdges:h}}var e=function(){function a(a,b,c){this.source=a,this.target=b,this.type=c}return a}();a.PowerEdge=e;var f=function(){function a(a,b,c,d){var e=this;if(this.linkAccessor=c,this.modules=new Array(a),this.roots=[],d)this.initModulesFromGroup(d);else{this.roots.push(new h);for(var f=0;a>f;++f)this.roots[0].add(this.modules[f]=new g(f))}this.R=b.length,b.forEach(function(a){var b=e.modules[c.getSourceIndex(a)],d=e.modules[c.getTargetIndex(a)],f=c.getType(a);b.outgoing.add(f,d),d.incoming.add(f,b)})}return a.prototype.initModulesFromGroup=function(a){var b=new h;this.roots.push(b);for(var c=0;cf;++f)for(var h=f+1;c>h;++h){var i=b[f],j=b[h];d[e++]={nEdges:this.nEdges(i,j),a:i,b:j}}return d},a.prototype.greedyMerge=function(){for(var a=0;a=this.R))return this.merge(c.a,c.b,a),!0}},a.prototype.nEdges=function(a,b){var c=a.incoming.intersection(b.incoming),d=a.outgoing.intersection(b.outgoing);return this.R-c.count()-d.count()},a.prototype.getGroupHierarchy=function(a){var c=this,d=[],f={};b(this.roots[0],f,d);var g=this.allEdges();return g.forEach(function(b){var f=c.modules[b.source],g=c.modules[b.target];a.push(new e("undefined"==typeof f.gid?b.source:d[f.gid],"undefined"==typeof g.gid?b.target:d[g.gid],b.type))}),d},a.prototype.allEdges=function(){var b=[];return a.getEdges(this.roots[0],b),b},a.getEdges=function(b,c){b.forAll(function(b){b.getEdges(c),a.getEdges(b.children,c)})},a}();a.Configuration=f;var g=function(){function a(a,b,c,d,e){void 0===b&&(b=new i),void 0===c&&(c=new i),void 0===d&&(d=new h),void 0===e&&(e=!1),this.id=a,this.outgoing=b,this.incoming=c,this.children=d,this.predefined=e}return a.prototype.getEdges=function(a){var b=this;this.outgoing.forAll(function(c,d){c.forAll(function(c){a.push(new e(b.id,c.id,d))})})},a.prototype.isLeaf=function(){return 0===this.children.count()},a.prototype.isIsland=function(){return 0===this.outgoing.count()&&0===this.incoming.count()},a}();a.Module=g;var h=function(){function a(){this.table={}}return a.prototype.count=function(){return Object.keys(this.table).length},a.prototype.intersection=function(b){var d=new a;return d.table=c(this.table,b.table),d},a.prototype.intersectionCount=function(a){return this.intersection(a).count()},a.prototype.contains=function(a){return a in this.table},a.prototype.add=function(a){this.table[a.id]=a},a.prototype.remove=function(a){delete this.table[a.id]},a.prototype.forAll=function(a){for(var b in this.table)a(this.table[b])},a.prototype.modules=function(){var a=[];return this.forAll(function(b){b.predefined||a.push(b)}),a},a}();a.ModuleSet=h;var i=function(){function a(){this.sets={},this.n=0}return a.prototype.count=function(){return this.n},a.prototype.contains=function(a){var b=!1;return this.forAllModules(function(c){b||c.id!=a||(b=!0)}),b},a.prototype.add=function(a,b){var c=a in this.sets?this.sets[a]:this.sets[a]=new h;c.add(b),++this.n},a.prototype.remove=function(a,b){var c=this.sets[a];c.remove(b),0===c.count()&&delete this.sets[a],--this.n},a.prototype.forAll=function(a){for(var b in this.sets)a(this.sets[b],b)},a.prototype.forAllModules=function(a){this.forAll(function(b){return b.forAll(a)})},a.prototype.intersection=function(b){var c=new a;return this.forAll(function(a,d){if(d in b.sets){var e=a.intersection(b.sets[d]),f=e.count();f>0&&(c.sets[d]=e,c.n+=f)}}),c},a}();a.LinkSets=i,a.getGroups=d}(b=a.powergraph||(a.powergraph={}))}(cola||(cola={}));var cola;!function(a){function b(a){a.fixed|=2,a.px=a.x,a.py=a.y}function c(a){a.fixed&=-7}function d(a){a.fixed|=4,a.px=a.x,a.py=a.y}function e(a){a.fixed&=-5}return a.d3adaptor=function(){var d=d3.dispatch("start","tick","end"),e=a.adaptor({trigger:function(a){d[a.type](a)},on:function(a,b){return d.on(a,b),e},kick:function(a){d3.timer(a)},drag:function(){var a=d3.behavior.drag().origin(function(a){return a}).on("dragstart.d3adaptor",b).on("drag.d3adaptor",function(a){a.px=d3.event.x,a.py=d3.event.y,e.resume()}).on("dragend.d3adaptor",c);return arguments.length?void this.call(a):a}});return e},a.adaptor=function(f){function g(a){return"function"==typeof r?+r.call(null,a):r}function h(a,b){a.length=b}function i(a){return"function"==typeof t?t(a):0}function j(a){return"number"==typeof a.source?a.source:a.source.index}function k(a){return"number"==typeof a.target?a.target:a.target.index}var l,m,n={},o=f.trigger,p=f.kick,q=[1,1],r=20,s=null,t=null,u=!1,v=!0,w=!1,x=[],y=[],z=[],A=null,B=[],C=[],D=null,E=null,F=null,G=.01,H=10,I=null;n.on=f.on,n.drag=f.drag,n.dragstart=b,n.dragend=c,n.mouseover=d,n.mouseout=e,n.tick=function(){if(G>l)return w=!1,o({type:"end",alpha:l=0,stress:m}),delete m,!0;{var a,b=x.length;B.length}E.locks.clear();for(var c=0;b>c;++c)if(a=x[c],a.fixed){("undefined"==typeof a.px||"undefined"==typeof a.py)&&(a.px=a.x,a.py=a.y);var d=[a.px,a.py];E.locks.add(c,d)}var e=E.rungeKutta();0===e?l=0:"undefined"!=typeof m&&(l=Math.abs(Math.abs(m/e)-1)),m=e;for(var c=0;b>c;++c)a=x[c],a.fixed?(a.x=a.px,a.y=a.py):(a.x=E.x[0][c],a.y=E.x[1][c]);o({type:"tick",alpha:l,stress:m})},n.nodes=function(a){if(!arguments.length){if(0===x.length&&B.length>0){var b=0;B.forEach(function(a){b=Math.max(b,a.source,a.target)}),x=new Array(++b);for(var c=0;b>c;++c)x[c]={}}return x}return x=a,n},n.groups=function(a){return arguments.length?(y=a,A={},y.forEach(function(a){"undefined"==typeof a.padding&&(a.padding=1),"undefined"!=typeof a.leaves&&a.leaves.forEach(function(b,c){(a.leaves[c]=x[b]).parent=a}),"undefined"!=typeof a.groups&&a.groups.forEach(function(b,c){(a.groups[c]=y[b]).parent=a})}),A.leaves=x.filter(function(a){return"undefined"==typeof a.parent}),A.groups=y.filter(function(a){return"undefined"==typeof a.parent}),n):y},n.powerGraphGroups=function(b){var c=a.powergraph.getGroups(x,B,J,A);return this.groups(c.groups),b(c),n},n.avoidOverlaps=function(a){return arguments.length?(u=a,n):u},n.handleDisconnected=function(a){return arguments.length?(v=a,n):v},n.flowLayout=function(a,b){return arguments.length||(a="y"),F={axis:a,getMinSeparation:"number"==typeof b?function(){return b}:b},n},n.links=function(a){return arguments.length?(B=a,n):B},n.constraints=function(a){return arguments.length?(C=a,n):C},n.distanceMatrix=function(a){return arguments.length?(D=a,n):D},n.size=function(a){return arguments.length?(q=a,n):q},n.defaultNodeSize=function(a){return arguments.length?(H=a,n):H},n.linkDistance=function(a){return arguments.length?(r="function"==typeof a?a:+a,s=null,n):"function"==typeof r?r():r},n.linkType=function(a){return t=a,n},n.convergenceThreshold=function(a){return arguments.length?(G="function"==typeof a?a:+a,n):G},n.alpha=function(a){return arguments.length?(a=+a,l?l=a>0?a:0:a>0&&(w||(w=!0,o({type:"start",alpha:l=a}),p(n.tick))),n):l};var J={getSourceIndex:j,getTargetIndex:k,setLength:h,getType:i};return n.symmetricDiffLinkLengths=function(b,c){return this.linkDistance(function(a){return b*a.length}),s=function(){a.symmetricDiffLinkLengths(B,J,c)},n},n.jaccardLinkLengths=function(b,c){return this.linkDistance(function(a){return b*a.length}),s=function(){a.jaccardLinkLengths(B,J,c)},n},n.start=function(){var b,c=this.nodes().length,d=c+2*y.length,e=(B.length,q[0]),f=q[1];s&&s();var h=new Array(d),i=new Array(d);z=new Array(d);var l=null,m=this.avoidOverlaps();x.forEach(function(a,b){a.index=b,"undefined"==typeof a.x&&(a.x=e/2,a.y=f/2),h[b]=a.x,i[b]=a.y});var o;D?o=D:(o=new a.shortestpaths.Calculator(d,B,j,k,g).DistanceMatrix(),l=a.Descent.createSquareMatrix(d,function(){return 2}),B.forEach(function(a){var b=j(a),c=k(a);l[b][c]=l[c][b]=1}));var p=a.Descent.createSquareMatrix(d,function(a,b){return o[a][b]});if(A&&"undefined"!=typeof A.groups){var b=c;y.forEach(function(){l[b][b+1]=l[b+1][b]=1e-6,p[b][b+1]=p[b+1][b]=.1,h[b]=0,i[b++]=0,h[b]=0,i[b++]=0})}else A={leaves:x,groups:[]};var r=C||[];F&&(J.getMinSeparation=F.getMinSeparation,r=r.concat(a.generateDirectedEdgeConstraints(c,B,F.axis,J)));var t=arguments.length>0?arguments[0]:0,u=arguments.length>1?arguments[1]:0,w=arguments.length>2?arguments[2]:0;this.avoidOverlaps(!1),E=new a.Descent([h,i],p),E.locks.clear();for(var b=0;c>b;++b){var I=x[b];if(I.fixed){I.px=I.x,I.py=I.y;var K=[I.x,I.y];E.locks.add(b,K)}}return E.threshold=G,E.run(t),r.length>0&&(E.project=new a.vpsc.Projection(x,y,A,r).projectFunctions()),E.run(u),this.avoidOverlaps(m),m&&(x.forEach(function(a,b){a.x=h[b],a.y=i[b]}),E.project=new a.vpsc.Projection(x,y,A,r,!0).projectFunctions(),x.forEach(function(a,b){h[b]=a.x,i[b]=a.y})),E.G=l,E.run(w),B.forEach(function(a){"number"==typeof a.source&&(a.source=x[a.source]),"number"==typeof a.target&&(a.target=x[a.target])}),x.forEach(function(a,b){a.x=h[b],a.y=i[b]}),!D&&v&&(a.applyPacking(a.separateGraphs(x,B),e,f,H),x.forEach(function(a,b){E.x[0][b]=a.x,E.x[1][b]=a.y})),n.resume()},n.resume=function(){return n.alpha(.1)},n.stop=function(){return n.alpha(0)},n.prepareEdgeRouting=function(b){I=new a.geom.TangentVisibilityGraph(x.map(function(a){return a.bounds.inflate(-b).vertices()}))},n.routeEdge=function(b,c){var d=[],e=new a.geom.TangentVisibilityGraph(I.P,{V:I.V,E:I.E}),f={x:b.source.x,y:b.source.y},g={x:b.target.x,y:b.target.y},h=e.addPoint(f,b.source.id),i=e.addPoint(g,b.target.id);e.addEdgeIfVisible(f,g,b.source.id,b.target.id),"undefined"!=typeof c&&c(e);var j=function(a){return a.source.id},k=function(a){return a.target.id},l=function(a){return a.length()},m=new a.shortestpaths.Calculator(e.V.length,e.E,j,k,l),n=m.PathFromNodeToNode(h.id,i.id);if(1===n.length||n.length===e.V.length)a.vpsc.makeEdgeBetween(b,b.source.innerBounds,b.target.innerBounds,5),d=[{x:b.sourceIntersection.x,y:b.sourceIntersection.y},{x:b.arrowStart.x,y:b.arrowStart.y}];else{for(var o=n.length-2,p=e.V[n[o]].p,q=e.V[n[0]].p,d=[b.source.innerBounds.rayIntersection(p.x,p.y)],r=o;r>=0;--r)d.push(e.V[n[r]].p);d.push(a.vpsc.makeEdgeTo(q,b.target.innerBounds,5))}return d},n.linkId=function(a){return j(a)+"-"+k(a)},n},a}(cola||(cola={})),RBTree=function(a){var b=function(a){var c=b.m[a];if(c.mod)return c.mod.exports;var d=c.mod={exports:{}};return c(d,d.exports),d.exports};return b.m={},b.m["./treebase"]=function(a){function b(){}function c(a){this._tree=a,this._ancestors=[],this._cursor=null}b.prototype.clear=function(){this._root=null,this.size=0},b.prototype.find=function(a){for(var b=this._root;null!==b;){var c=this._comparator(a,b.data);if(0===c)return b.data;b=b.get_child(c>0)}return null},b.prototype.findIter=function(a){for(var b=this._root,c=this.iterator();null!==b;){var d=this._comparator(a,b.data);if(0===d)return c._cursor=b,c;c._ancestors.push(b),b=b.get_child(d>0)}return null},b.prototype.lowerBound=function(a){return this._bound(a,this._comparator)},b.prototype.upperBound=function(a){function b(a,b){return c(b,a)}var c=this._comparator;return this._bound(a,b)},b.prototype.min=function(){var a=this._root;if(null===a)return null;for(;null!==a.left;)a=a.left;return a.data},b.prototype.max=function(){var a=this._root;if(null===a)return null;for(;null!==a.right;)a=a.right;return a.data},b.prototype.iterator=function(){return new c(this)},b.prototype.each=function(a){for(var b,c=this.iterator();null!==(b=c.next());)a(b)},b.prototype.reach=function(a){for(var b,c=this.iterator();null!==(b=c.prev());)a(b)},b.prototype._bound=function(a,b){for(var c=this._root,d=this.iterator();null!==c;){var e=this._comparator(a,c.data);if(0===e)return d._cursor=c,d;d._ancestors.push(c),c=c.get_child(e>0)}for(var f=d._ancestors.length-1;f>=0;--f)if(c=d._ancestors[f],b(a,c.data)>0)return d._cursor=c,d._ancestors.length=f,d;return d._ancestors.length=0,d},c.prototype.data=function(){return null!==this._cursor?this._cursor.data:null},c.prototype.next=function(){if(null===this._cursor){var a=this._tree._root;null!==a&&this._minNode(a)}else if(null===this._cursor.right){var b;do{if(b=this._cursor,!this._ancestors.length){this._cursor=null;break}this._cursor=this._ancestors.pop()}while(this._cursor.right===b)}else this._ancestors.push(this._cursor),this._minNode(this._cursor.right);return null!==this._cursor?this._cursor.data:null},c.prototype.prev=function(){if(null===this._cursor){var a=this._tree._root;null!==a&&this._maxNode(a)}else if(null===this._cursor.left){var b;do{if(b=this._cursor,!this._ancestors.length){this._cursor=null;break}this._cursor=this._ancestors.pop()}while(this._cursor.left===b)}else this._ancestors.push(this._cursor),this._maxNode(this._cursor.left);return null!==this._cursor?this._cursor.data:null},c.prototype._minNode=function(a){for(;null!==a.left;)this._ancestors.push(a),a=a.left;this._cursor=a},c.prototype._maxNode=function(a){for(;null!==a.right;)this._ancestors.push(a),a=a.right;this._cursor=a},a.exports=b},b.m.__main__=function(a){function c(a){this.data=a,this.left=null,this.right=null,this.red=!0}function d(a){this._root=null,this._comparator=a,this.size=0}function e(a){return null!==a&&a.red}function f(a,b){var c=a.get_child(!b);return a.set_child(!b,c.get_child(b)),c.set_child(b,a),a.red=!0,c.red=!1,c}function g(a,b){return a.set_child(!b,f(a.get_child(!b),!b)),f(a,b)}var h=b("./treebase");c.prototype.get_child=function(a){return a?this.right:this.left},c.prototype.set_child=function(a,b){a?this.right=b:this.left=b},d.prototype=new h,d.prototype.insert=function(a){var b=!1;if(null===this._root)this._root=new c(a),b=!0,this.size++;else{var d=new c(void 0),h=0,i=0,j=null,k=d,l=null,m=this._root;for(k.right=this._root;;){if(null===m?(m=new c(a),l.set_child(h,m),b=!0,this.size++):e(m.left)&&e(m.right)&&(m.red=!0,m.left.red=!1,m.right.red=!1),e(m)&&e(l)){var n=k.right===j;m===l.get_child(i)?k.set_child(n,f(j,!i)):k.set_child(n,g(j,!i))}var o=this._comparator(m.data,a);if(0===o)break;i=h,h=0>o,null!==j&&(k=j),j=l,l=m,m=m.get_child(h)}this._root=d.right}return this._root.red=!1,b},d.prototype.remove=function(a){if(null===this._root)return!1;var b=new c(void 0),d=b;d.right=this._root;for(var h=null,i=null,j=null,k=1;null!==d.get_child(k);){var l=k;i=h,h=d,d=d.get_child(k);var m=this._comparator(a,d.data);if(k=m>0,0===m&&(j=d),!e(d)&&!e(d.get_child(k)))if(e(d.get_child(!k))){var n=f(d,k);h.set_child(l,n),h=n}else if(!e(d.get_child(!k))){var o=h.get_child(!l);if(null!==o)if(e(o.get_child(!l))||e(o.get_child(l))){var p=i.right===h;e(o.get_child(l))?i.set_child(p,g(h,l)):e(o.get_child(!l))&&i.set_child(p,f(h,l));var q=i.get_child(p);q.red=!0,d.red=!0,q.left.red=!1,q.right.red=!1}else h.red=!1,o.red=!0,d.red=!0}}return null!==j&&(j.data=d.data,h.set_child(h.right===d,d.get_child(null===d.left)),this.size--),this._root=b.right,null!==this._root&&(this._root.red=!1),null!==j},a.exports=d},b("__main__")}(window);var cola;!function(a){var b={};return b.PADDING=10,b.GOLDEN_SECTION=(1+Math.sqrt(5))/2,b.FLOAT_EPSILON=1e-4,b.MAX_INERATIONS=100,a.applyPacking=function(a,c,d,e,f){function g(a){function b(a){var b=Number.MAX_VALUE,c=Number.MAX_VALUE,d=0,f=0;a.array.forEach(function(a){var g="undefined"!=typeof a.width?a.width:e,h="undefined"!=typeof a.height?a.height:e;g/=2,h/=2,d=Math.max(a.x+g,d),b=Math.min(a.x-g,b),f=Math.max(a.y+h,f),c=Math.min(a.y-h,c)}),a.width=d-b,a.height=f-c}a.forEach(function(a){b(a)})}function h(a){a.forEach(function(a){var b={x:0,y:0};a.array.forEach(function(a){b.x+=a.x,b.y+=a.y}),b.x/=a.array.length,b.y/=a.array.length;var c={x:b.x-a.width/2,y:b.y-a.height/2},d={x:a.x-c.x,y:a.y-c.y};a.array.forEach(function(a){a.x=a.x+d.x+p/2-r/2,a.y=a.y+d.y+q/2-s/2})})}function i(a){var c=Number.POSITIVE_INFINITY,d=0;a.sort(function(a,b){return b.height-a.height}),t=a.reduce(function(a,b){return a.widtht||n>b.FLOAT_EPSILON;){if(1!=k)var o=f-(f-e)/b.GOLDEN_SECTION,h=j(a,o);if(0!=k)var p=e+(f-e)/b.GOLDEN_SECTION,i=j(a,p);if(m=Math.abs(o-p),n=Math.abs(h-i),c>h&&(c=h,d=o),c>i&&(c=i,d=p),h>i?(e=o,o=p,h=i,k=1):(f=p,p=o,i=h,k=0),g++>100)break}j(a,d)}function j(a,b){v=[],r=0,s=0,u=o;for(var c=0;c=a.height&&v[e].x+v[e].width+a.width+b.PADDING-c<=b.FLOAT_EPSILON){d=v[e];break}v.push(a),void 0!==d?(a.x=d.x+d.width+b.PADDING,a.y=d.bottom,a.space_left=a.height,a.bottom=a.y,d.space_left-=a.height+b.PADDING,d.bottom+=a.height+b.PADDING):(a.y=u,u+=a.height+b.PADDING,a.x=n,a.bottom=a.y,a.space_left=a.height),a.y+a.height-s>-b.FLOAT_EPSILON&&(s=a.y+a.height-o),a.x+a.width-r>-b.FLOAT_EPSILON&&(r=a.x+a.width-n)}function l(a){var c=0;return a.forEach(function(a){return c+=a.width+b.PADDING}),c}function m(){return r/s}var n=0,o=0,p=c,q=d,f="undefined"!=typeof f?f:1,e="undefined"!=typeof e?e:0,r=0,s=0,t=0,u=0,v=[];0!=a.length&&(g(a),i(a),h(a))},a.separateGraphs=function(a,b){function c(a,b){if(void 0===d[a.index]){b&&(g++,f.push({array:[]})),d[a.index]=g,f[g-1].array.push(a);var h=e[a.index];if(h)for(var i=0;i